javascript原型继承混淆

时间:2016-02-04 02:48:41

标签: javascript oop inheritance prototype

给出了像这样实现继承的标准方法

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;

4 个答案:

答案 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.prototypeSubClass.prototype现在引用相同的对象

答案 2 :(得分:0)

JavaScript的语法可能有些令人困惑。在JS中,没有类继承,但基于实例的继承。实例的父级也称为其原型。

当您编写instance.somethinginstance['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继承。

Sample MyClass.prototype console inspection

但是,正如我之前所说,函数的默认.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继承。

enter image description here

相关问题