Note:
正如答案所说,由于问题和我的评论中描述的一些问题,问题中提出的代码确实实现了继承(否则它变成了答案而不是问题......) . 它按预期工作 a fake of 继承(甚至不是原型) .
- Summary
简而言之,使它与我们编写一般的OO语言而不是javascript类似,但保持继承是正确的 .
- The story
Object.create是实现原型继承的好方法,但它对于大脑和 new 粉丝来说有点混乱 .
我们可以通过各种方式编写javascript代码,就像我们使用伪经典模式编写其他OO语言一样 . 因为它是 pseudo - 经典,我们必须正确处理javascript的基础原型继承 .
我想要找到的是一种可以实现伪古典继承的方法 right on the class declaration . 演示代码放在帖子的后面,它按预期工作,但是,有一些烦人的事情:
-
我无法在类声明中删除
return
,否则继承将无效 . -
除了在类声明中传递
this
之外我没办法让返回的闭包知道this
是什么 . -
我也想摆脱
function (instance, _super) {
,但还没有好主意 . -
不继承类的静态(自己的属性) .
解决方案比现有框架更多的是一些语法糖,一个好的模式是适用的 .
_extends
功能:
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;
});
}
Xyz
班:
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
5 回答
不,不,这不行 . 你在JavaScript中继承都是错的 . 你的代码给了我偏头痛 .
在JavaScript中创建伪古典继承模式
如果你想要类似于JavaScript中的类,那么有很多库可以提供给你 . 例如,使用augment,您可以按如下方式重构代码:
我不了解你,但对我而言,这看起来很像C或Java中的经典继承 . 如果这解决了你的问题,太好了!如果不是那么继续阅读 .
原型级同构
在很多方面,原型与类相似 . 事实上,原型和类是如此相似,我们可以使用原型来建模类 . 首先让我们来看看how prototypal inheritance really works:
上图是从following answer拍摄的 . 我建议你仔细阅读 . 该图显示了我们:
每个构造函数都有一个名为
prototype
的属性,它指向构造函数的原型对象 .每个原型都有一个名为
constructor
的属性,它指向原型对象的构造函数 .我们从构造函数创建一个实例 . 但是实例实际上继承自
prototype
,而不是构造函数 .这是非常有用的信息 . 传统上我们've always created a constructor function first and then we'已设置其
prototype
属性 . 但是,这些信息告诉我们,我们可以先创建一个原型对象,然后在其上定义constructor
属性 .例如,传统上我们可以写:
然而,使用我们新发现的知识,我们可能会写同样的东西:
正如您所看到的,在JavaScript中很容易实现封装 . 你需要做的就是侧身思考 . 然而,继承是一个不同的问题 . 你需要做更多的工作才能实现继承 .
继承与超级
看看如何
augment
achieves inheritance:请注意,最后三行与上一节中的
CLASS
相同:这告诉我们,一旦我们有了一个原型对象,我们需要做的就是获取它的构造函数属性并返回它 .
增强的前三行用于:
获取基类原型 .
使用
Object.create
创建派生类原型 .使用指定的属性填充派生类原型 .
这就是JavaScript中继承的全部内容 . 如果你想创建自己的经典继承模式,那么你应该考虑相同的思路 .
拥抱真正的原型继承
每个值得他们盐的JavaScript程序员都会告诉你prototypal inheritance is better than classical inheritance . 然而,来自具有经典继承的语言的新手总是试图在原型继承之上实现经典继承,并且它们通常会失败 .
它们失败不是因为它不可能在原型继承之上实现经典继承,但是因为要在原型继承之上实现经典继承,首先需要了解true prototypal inheritance works .
然而,一旦你理解了真正的原型继承,你就永远不会想要回归经典继承 . 我也tried到implement作为新手的原型继承之上的经典继承 . 既然我理解了真正的原型继承是如何工作的,那么我编写这样的代码:
以上
extend
函数与augment非常相似 . 但是,它不返回构造函数,而是返回原型对象 . 这实际上是一个非常巧妙的技巧,它允许继承静态属性 . 您可以使用extend
创建一个类,如下所示:继承就是这么简单:
但请记住,
extend
不会返回构造函数 . 它返回原型对象 . 这意味着您无法使用new
关键字来创建类的实例 . 相反,您需要使用new
作为方法,如下所示:这实际上是件好事 .
new
关键字是considered harmful,我强烈建议您使用stop using it . 例如,它是not possible to use apply with the new keyword . 但是,可以将apply
与new
方法一起使用,如下所示:由于
Abc
和Xyz
不是构造函数,我们不能使用instanceof
来测试对象是Abc
还是Xyz
的实例 . 然而,这不是问题,因为JavaScript有一个名为isPrototypeOf的方法,它测试一个对象是否是另一个对象的原型:实际上
isPrototypeOf
比instanceof
更强大,因为它允许我们测试一个类是否扩展另一个类:除了这个微小的改变,其他一切都像以前一样工作:
亲眼看看演示:http://jsfiddle.net/Jee96/
真正的原型继承还提供了什么?真正原型继承的最大优点之一是普通属性和静态属性之间没有区别,允许您编写如下代码:
请注意,我们可以通过调用
this.new
从类本身创建类的实例 . 如果尚未定义this.constructor
,则返回新的未初始化实例 . 否则返回一个新的初始化实例 .另外因为
Xyz
是原型对象,我们可以直接访问Xyz.empty
(即empty
是Xyz
的静态属性) . 这也意味着静态属性会自动继承,并且与普通属性没有区别 .最后,因为类可以在类定义中作为
this
访问,所以您可以创建嵌套类,这些嵌套类通过使用extend
从它们嵌套的类继承,如下所示:请亲自观看演示:http://jsfiddle.net/Jee96/1/
有关如何做你想做的事情的详尽的教程 .
oop-concepts
pseudo-classical-pattern
all-one-constructor-pattern
我知道这不能回答你的问题,因为据我所知,没有好办法把所有东西放在函数构造函数中并让它使用原型 .
正如我评论的那样;如果您在使用JavaScript语法时遇到问题,那么typescript可能是一个不错的选择 .
这是一个帮助函数,我用它来继承和覆盖(调用super)使用JavaScript(没有Object.create)
即使您找到了编写辅助函数的方法并使JS构造函数看起来像Java类,您也必须understand prototype .
你总是可以尝试jOOP,虽然它确实需要jQuery .
https://github.com/KodingSykosis/jOOP
http://jsfiddle.net/kodingsykosis/PrQWu/
我相信你正在寻找比这更多的功能,但如果你想从另一个类继承一堆方法,你可以这样做
http://cdpn.io/Jqhpc