这是我应该期望看到使用Javascript原型继承的行为吗?

时间:2014-11-16 18:14:02

标签: javascript google-chrome inheritance

我是Javascript的新手并且对使用继承带来了一个问题

到目前为止,本文一直很有帮助(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#More_flexible_constructors),但我在Chrome调试器中观察到的行为似乎与我期望看到的不相符。

我有两个案例:

Base = function () {
    this.value = 0;
};

Base.prototype.constructor = Base;

Derived = function () {
    Base.call(this);
};

Derived.prototype = new Base();
Derived.prototype.constructor = Derived;

在调试器中我看到了:

enter image description here

enter image description here

完成作业后,我看到了这个

enter image description here

实例中的值已更改,但原型中的值未更改。这是预期的吗?

我不太明白的第二种方法是这一点(此处再次引用 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#More_flexible_constructors(请参阅第39页底部截断的代码;重新访问属性继承')

Base = function () {
};

Base.prototype.constructor = Base;
Base.prototype.value = 0;

// Derived as before...

enter image description here

和作业后

enter image description here

已添加值作为新属性。难道这不会改变原型中的价值吗?或者我是否明确需要通过原型访问该值 - 例如derived.value.prototype.value = 5

非常感谢有关此事的任何信息!

谢谢!

更新

感谢所有回复的人,事实证明这与我在适当的时候不使用Object.create有关。我将我的代码更新为:

enter image description here

在调试器中我得到了我的预期:

enter image description here

这看起来不错! :)

enter image description here

感谢@sixfingeredman和@Bergi的帮助!

2 个答案:

答案 0 :(得分:2)

首先,如果不是主题,请删除此行:

Base.prototype.constructor = Base;

没有做任何有用的事情。

现在回答你的问题,是的,行为是预期的。想象一下,如果它更新了.prototype。由于.prototype在所有实例之间共享,因此所有实例都会看到更新。那肯定不是你想要的。

当你这样做时:

var derived = new Derived();

您创建了一个继承自Derived.prototype

的新对象

当你这样做时:

derived.value = 1;

您直接为该新对象指定了值。

所以在分配之前,继承链看起来像这样:

  derived            Derived.prototype      Base.prototype       Object.prototype
+-----------+         +-----------+         +-----------+         +-----------+
|           |         |           |         |           |         |           |
|           |---------|  value:0  |---------|           |---------|           |
|           |         |           |         |           |         |           |
+-----------+         +-----------+         +-----------+         +-----------+

分配后,它看起来像这样:

  derived            Derived.prototype      Base.prototype       Object.prototype
+-----------+         +-----------+         +-----------+         +-----------+
|           |         |           |         |           |         |           |
|  value:1  |---------|  value:0  |---------|           |---------|           |
|           |         |           |         |           |         |           |
+-----------+         +-----------+         +-----------+         +-----------+

因此,在分配之前,如果您在value对象上查找derived,则无法找到它,因此它会跳转到Derived.prototype,在那里找到它

但在作业完成后,value会直接在derived对象上找到。


用你的第二种方式,原型链将开始看起来像这样:

  derived            Derived.prototype      Base.prototype       Object.prototype
+-----------+         +-----------+         +-----------+         +-----------+
|           |         |           |         |           |         |           |
|           |---------|           |---------|  value:0  |---------|           |
|           |         |           |         |           |         |           |
+-----------+         +-----------+         +-----------+         +-----------+

因此,在value上查找derived时,它会在找到derived属性之前从Derived.prototypeBase.prototype遍历到value


因此,假设您从Derived构造函数创建了一堆对象。上面的草图会发生变化,因此您创建的每个对象都会指向Derived.prototype

  derived_1
+-----------+        
|           |
|           |
|           |
+-----------+
             \______
                    \
                     \
  derived_2          Derived.prototype      Base.prototype       Object.prototype
+-----------+         +-----------+         +-----------+         +-----------+
|           |         |           |         |           |         |           |
|           |---------|           |---------|  value:0  |---------|           |
|           |         |           |         |           |         |           |
+-----------+         +-----------+         +-----------+         +-----------+
                      /
               ______/
  derived_3   /
+-----------+        
|           |
|           |
|           |
+-----------+        

现在您可以看到为什么不想更新原型。

如果我们执行了derived_1.value = 42并且更新了Derived.prototype对象,那么当您从valuederived_2查找derived_3时,您就会' d获取您分配给derived_1的值。

答案 1 :(得分:2)

  

已添加值作为新属性。难道这不会改变原型中的值吗?

不,这种行为是预料之中的。属性仅在" get"上继承,而不是在设置上继承。将值分配给对象 1 的属性后,将更改(或创建)该对象上的属性。

1:除了accessor property (setter function) on the prototype

  

或者我是否明确需要通过原型来访问该值 - 例如derived.value.prototype.value = 5

要更改原型上的值,您需要在原型上分配它,是的。在你的情况下,那将是

Derived.prototype.value = 5;

Object.getPrototypeOf(derived).value = 5;

顺便说一下,请注意Base上的属性(在Derived.prototype构造函数中按实例创建)根本不存在 - 请参阅What is the reason to use the 'new' keyword at Derived.prototype = new Base。而不是Derived.prototype = new Base;你应该使用

Derived.prototype = Object.create(Base.prototype);