给出了像这样实现继承的标准方法
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
为什么需要做
SubClass.prototype = Object.create(BaseClass.prototype);
并最终得到类似
的内容function F(){}
F.prototype = BaseClass.prototype;
SubClass.prototype = new F();
而不只是做
Subclass.prototype = BaseClass.prototype;
答案 0 :(得分:2)
为JavaScript中的内容分配值实际上只是复制引用(除非使用基本类型)。所以当你这样做时:
Subclass.prototype = BaseClass.prototype;
你真正做的是将SubClass
的原型分配到内存中与BaseClass
原型相同的位置,因此您所做的任何与原型相关的更改SubClass
也会影响BaseClass
。这是一个小例子:
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = BaseClass.prototype;
SubClass.prototype.constructor = SubClass;
SubClass.prototype.subClassFunction = function(){
console.log("Added this to SubClass");
}
var baseObj = new BaseClass();
baseObj.subClassFunction(); // => "Added this to SubClass"
这就是你想要使用
的原因SubClass.prototype = Object.create(BaseClass.prototype);
因为它会使用指定的原型创建 new 和 unique 对象。
您可以详细了解此功能的工作原理here。
答案 1 :(得分:0)
说BaseClass
有方法toString
:
BaseClass.prototype.toString = function() {
return 'foo'
}
但您重新定义了toString
中的SubClass
方法:
SubClass.prototype.toString = function() {
return 'bar'
}
你会期待:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'foo'
s.toString() //=> 'bar'
但是如果你使用赋值来创建继承,你会得到的是:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'bar'
s.toString() //=> 'bar'
由于BaseClass.prototype
和SubClass.prototype
现在引用相同的对象
答案 2 :(得分:0)
JavaScript的语法可能有些令人困惑。在JS中,没有类继承,但基于实例的继承。实例的父级也称为其原型。
当您编写instance.something
或instance['something']
时,JS引擎会查看该实例以查看它是否具有名为something
的成员。如果它没有,那么它会查看实例的原型。如果该对象没有成员something
,它会一次又一次地查看原型的原型,直到它找到属性或到达继承自null
的实例。在这种情况下,它只会返回undefined
。
函数有一个名为prototype
的特殊属性,这是其他内容。函数.prototype
是一个具有constructor
属性的简单对象它引用了函数本身。使用new
关键字创建对象时,该对象的原型将设置为函数的.prototype
属性。这就是混淆的地方:构造函数的.prototype
属性可以看作是使用所述构造函数创建的所有实例的默认原型。
因此,当您通过编写类似的内容向类添加方法时:
MyClass.prototype.foo = function() {
alert('foo');
};
...您实际上将该函数存储在所有MyClass实例的原型中。当JS引擎查看MyClass的实例时,它将查找它无法找到的foo
成员。然后它将查看实例的原型,该原型恰好设置为MyClass.prototype
,它将找到foo
成员并获取它。
在实例原型和函数.prototype
之间做出区分非常重要,但大多数人都没有意识到这一点。当他们谈到课程的原型时,他们会谈论MyClass.prototype
。在许多浏览器中,可以通过__proto__
访问实例原型,但这不是JavaScript的标准功能,不应该在您的代码中使用。
现在让我们看看你用来模拟类继承的代码。
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
Object.create(parent)
可视为执行此操作的函数:
return {
__proto__ : parent
};
换句话说,它创建一个空白Object,其原型是传递的对象。由于所有SubClass实例都将继承自Subclass.prototype
,因此将SubClass.prototype
替换为继承自BaseClass.prototype
的对象,可确保所有SubClass实例也从BaseClass继承。
但是,正如我之前所说,函数的默认.prototype
属性是一个空对象,其.constructor
设置为函数本身。因此,通过再次手动设置.constructor
,我们可以完美地模仿默认的原型行为。如果我们不这样做,那么instance.constructor
将返回原型链中第一个定义的.constructor
属性,该属性将为BaseClass
。除非我们的代码实际上取决于constructor
属性,否则它在行为方面并没有真正改变任何东西,但它更安全。
最后一点,就像我之前提到的那样,我终于可以发布这个答案了,你不能只做SubClass.prototype = BaseClass.prototype;
,因为那样你就无法在没有添加的情况下向SubClass添加方法他们到BaseClass。
答案 3 :(得分:0)
继承,__ proto __ :
当对象 SubClass
继承自另一个对象 BaseClass
时,在JavaScript中意味着存在特殊属性SubClass.__proto__ = BaseClass
代码:
function BaseClass() {
}
function SubClass() {
}
var BaseClass = new BaseClass();
var SubClass = new SubClass();
BaseClass.a = 5;
SubClass.b = 10;
SubClass.__proto__ = BaseClass;
console.log(SubClass);
输出
此处, BaseClass
由 SubClass
和BaseClass variable is accessable through the SubClass
继承。