Javascript 如何实现类声明上的伪经典继承权?

Javascript 如何实现类声明上的伪经典继承权?,javascript,inheritance,types,prototype,Javascript,Inheritance,Types,Prototype,注意: 正如答案所表明的,由于问题和我的评论中描述的一些问题,问题中提出的代码并没有真正实现继承(否则它将成为一个答案而不是一个问题…)。它的工作原理与预期一样,是继承的伪继承(甚至不是原型) 摘要 简言之,使其与我们编写的通用OO语言(而不是javascript)类似,但保持继承正确 故事 是实现原型遗传的好方法,但对于类型的大脑和新的粉丝来说,这有点让人困惑 我们可以通过多种方式编写javascript代码,就像使用伪经典模式编写其他OO语言一样。由于它是伪经典的,我们必须正确处理jav

注意:

正如答案所表明的,由于问题和我的评论中描述的一些问题,问题中提出的代码并没有真正实现继承(否则它将成为一个答案而不是一个问题…)。它的工作原理与预期一样,是继承的伪继承(甚至不是原型)


  • 摘要

    简言之,使其与我们编写的通用OO语言(而不是javascript)类似,但保持继承正确

  • 故事

    是实现原型遗传的好方法,但对于类型的大脑和新的粉丝来说,这有点让人困惑

    我们可以通过多种方式编写javascript代码,就像使用伪经典模式编写其他OO语言一样。由于它是伪经典的,我们必须正确处理javascript的底层原型继承

    我想找到的是一种方法,可以在类声明上实现伪经典继承。演示代码放在帖子的后面,它可以正常工作,但是,有一些恼人的事情:

  • 我无法在类声明中删除
    return
    ,否则继承将不起作用

  • 除了在类声明中传递
    this
    之外,我没有其他方法使返回的闭包知道什么是
    this

  • 我还想去掉
    函数(例如,_super){
    ,但还没有一个好主意

  • 类的静态(自身属性)不会被继承

  • 一个解决方案比现有的框架更需要一些语法上的糖分,一个好的模式是适用的


\u扩展了
功能:

function _extends(baseType) {
    return function (definition) {
        var caller=arguments.callee.caller;
        var instance=this;

        if(!(instance instanceof baseType)) {
            (caller.prototype=new baseType()).constructor=caller;
            instance=new caller();
        }

        var _super=function () {
            baseType.apply(instance, arguments);
        };

        definition(instance, _super);
        return instance;
    };
}
Abc
课程:

function Abc(key, value) {
    return _extends(Object).call(this, function (instance, _super) {
        instance.What=function () {
            alert('What');
        };

        instance.getValue=function () {
            return 333+Number(value);
        };

        instance.Value=instance.getValue();
        instance.Key=key;
    });
}
function Xyz(key, value) {
    return _extends(Abc).call(this, function (instance, _super) {
        _super(key, value);

        instance.That=function () {
            alert('That');
        };
    });
}
Xyz
类:

function Abc(key, value) {
    return _extends(Object).call(this, function (instance, _super) {
        instance.What=function () {
            alert('What');
        };

        instance.getValue=function () {
            return 333+Number(value);
        };

        instance.Value=instance.getValue();
        instance.Key=key;
    });
}
function Xyz(key, value) {
    return _extends(Abc).call(this, function (instance, _super) {
        _super(key, value);

        instance.That=function () {
            alert('That');
        };
    });
}
示例代码:

var x=new Xyz('x', '123');
alert([x.Key, x.Value].join(': ')+'; isAbc: '+(x instanceof Abc));

var y=new Xyz('y', '456');
alert([y.Key, y.Value].join(': ')+'; isAbc: '+(y instanceof Abc));

var it=new Abc('it', '789');
alert([it.Key, it.Value].join(': ')+'; isAbc: '+(it instanceof Abc));
alert([it.Key, it.Value].join(': ')+'; isXyz: '+(it instanceof Xyz));

x.What();
y.That();

it.What();
it.That(); // will throw; it is not Xyz and does not have That method

我知道这并不能回答你的问题,因为据我所知,没有什么好方法可以将所有内容都放在函数构造函数中并让它使用原型

正如我所评论的,如果您在JavaScript语法方面有问题,那么这可能是一个不错的选择

下面是一个助手函数,我使用JavaScript(不带Object.create)继承和重写(调用super)


即使你找到了一种方法来编写帮助函数并使JS构造函数看起来像Java类,你也必须这样做。

不。不。不。不。这不行。你在JavaScript中做继承完全错了。你的代码让我头疼

在JavaScript中创建伪经典继承模式 如果您需要类似于JavaScript中的类的东西,那么有很多库提供给您。例如,使用JavaScript,您可以按如下方式重新构造代码:

var augment = require("augment");

var ABC = augment(Object, function () {
    this.constructor = function (key, value) {
        this.key = key;
        this.value = value;
    };

    this.what = function () {
        alert("what");
    };
});

var XYZ = augment(ABC, function (base) {
    this.constructor = function (key, value) {
        base.constructor.call(this, key, value);
    };

    this.that = function () {
        alert("that");
    };
});
var Abc = extend(Object, function () {
    this.constructor = function (key, value) {
        this.value = 333 + Number(value);
        this.key = key;
    };

    this.what = function () {
        alert("what");
    };
});
var x = Xyz.new("x", "123");
var y = Xyz.new("y", "456");
var it = Abc.new("it", "789");
var it = Abc.new.apply(null, ["it", "789"]);
var ClassA = extend(Object, function () {
    var ClassB = extend(this, function () {
        // class definition
    });

    // rest of the class definition

    alert(this.isPrototypeOf(ClassB)); // true
});
太好了!如果C++解决了你的问题,那就太好了。如果java不继续读下去,

原型类同构

在很多方面,原型与类相似。事实上,原型和类非常相似,我们可以使用原型来建模类。首先,让我们来看看:

上面的图片是从中拍摄的。我建议您仔细阅读。图表显示了我们:

  • 每个构造函数都有一个名为
    prototype
    的属性,该属性指向构造函数的prototype对象
  • 每个原型都有一个名为
    constructor
    的属性,该属性指向原型对象的构造函数
  • 我们从构造函数创建一个实例。但是实例实际上是从
    原型继承的,而不是从构造函数继承的
  • 这是非常有用的信息。传统上,我们总是先创建构造函数,然后设置其
    原型
    属性。但是,这些信息告诉我们,我们可以先创建原型对象,然后在其上定义
    构造函数
    属性

    例如,传统上我们可以写:

    function ABC(key, value) {
        this.key = key;
        this.value = value;
    }
    
    ABC.prototype.what = function() {
        alert("what");
    };
    
    然而,利用我们新发现的知识,我们可以写下如下内容:

    var ABC = CLASS({
        constructor: function (key, value) {
            this.key = key;
            this.value = value;
        },
        what: function () {
            alert("what");
        }
    });
    
    function CLASS(prototype) {
        var constructor = prototype.constructor;
        constructor.prototype = prototype;
        return constructor;
    }
    
    正如您所见,封装在JavaScript中很容易实现。您所需要做的就是从侧面思考。但是继承是另一个问题。您需要做更多的工作来实现继承

    继承与超越 看看
    是如何增强的

    请注意,最后三行与上一节中的
    CLASS
    相同:

    function CLASS(prototype) {
        var constructor = prototype.constructor;
        constructor.prototype = prototype;
        return constructor;
    }
    
    这告诉我们,一旦我们有了一个原型对象,我们需要做的就是获取它的构造函数属性并返回它

    前三行增强用于:

  • 获取基类原型
  • 使用
    对象创建派生类原型。创建
  • 使用指定的属性填充派生类原型
  • 这就是JavaScript中继承的全部内容。如果您想创建自己的经典继承模式,那么您应该按照同样的思路思考

    拥抱真正的原型遗传 每一个称职的JavaScript程序员都会告诉你这一点。然而,来自经典继承语言的新手总是试图在原型继承的基础上实现经典继承,而他们通常会失败

    它们失败不是因为不可能在原型继承的基础上实现经典继承,而是因为要在原型继承的基础上实现经典继承,首先需要了解如何实现

    然而,一旦你理解了真正的原型继承,你就再也不想回到古典继承了。作为一个新手,我也开始在原型继承的基础上学习古典继承。现在,我明白了真正的原型是如何
    var it = Abc.new.apply(null, ["it", "789"]);
    
    alert(x.key + ": " + x.value + "; isAbc: " + Abc.isPrototypeOf(x));
    alert(y.key + ": " + y.value + "; isAbc: " + Abc.isPrototypeOf(y));
    
    alert(it.key + ": " + it.value + "; isAbc: " + Abc.isPrototypeOf(it));
    alert(it.key + ": " + it.value + "; isXyz: " + Xyz.isPrototypeOf(it));
    
    alert(Abc.isPrototypeOf(Xyz)); // true
    
    x.what();
    y.that();
    
    it.what();
    it.that(); // will throw; it is not Xyz and does not have that method
    
    var Xyz = extend(Abc, function (base) {
        this.empty = this.new();
    
        this.constructor = function (key, value) {
            base.constructor.call(this, key, value);
        };
    
        this.that = function () {
            alert("that");
        };
    });
    
    var ClassA = extend(Object, function () {
        var ClassB = extend(this, function () {
            // class definition
        });
    
        // rest of the class definition
    
        alert(this.isPrototypeOf(ClassB)); // true
    });
    
    var myClass = $.cls({
        main: function() {
            $('body').append('My App is loaded <br/>');
        }
    });
    
    var mySecondClass = $.cls({
        main: function() {
            this._super();
            $('body').append('My Second App is loaded <br/>');
        }
    }, myClass);
    
    var app = new mySecondClass();
    
    var Parent = function Parent () {
      this.fname = 'Bob';
      this.lname = 'Jones';
    };
    Parent.prototype.getFname = function getFname () {
      return this.fname;
    };
    Parent.prototype.getLname = function getLname () {
      return this.lname;
    };
    
    var Child = function Child () {
      this.fname = 'Jim';
    };
    Child.prototype = Parent.prototype;
    
    var child = new Child();
    document.write(child.getFname()); //=> Jim