Javascript中的继承和Object.Create

时间:2011-09-14 12:10:05

标签: javascript prototypal-inheritance object-create

看看这段代码:

        var Test = {
        options: {
            name: 'foo'
        },
        name: 'foo',
        init: function (name) {
            this.name = name;
            this.options.name = name;
        }
    };

    var dict = {};

    for (var i = 0; i < 3; i++) {
        var obj = Object.create(Test);
        obj.init(i);
        dict[i] = obj;
    }

我不明白为什么对象dict中的dict [X] .options.name中的所有属性 具有相同值(2)的值,并且dict [X] .name中的属性具有不同的值 ?

3 个答案:

答案 0 :(得分:1)

看起来与通过引用传递值有关。

对象Test包含对属性options中另一个对象的引用。当创建Test的新实例时,新实例将获得对现有options实例的引用,而不是获取该对象的新副本。

粗略的图像会是这样的 enter image description here

您可以通过在代码底部添加以下语句来检查它

alert(Test.options== dict[0].options);

答案 1 :(得分:1)

documentation很清楚:

  

使用指定的原型对象和属性创建一个新对象。

因此Test将成为新对象的原型。所有实例都引用相同的原型,而options是一个对象,它们也共享对此的引用。

关系如下:

+------------+      +---------+       +--------+
| Instance 1 |----->| Test    |       | Object |
+------------+      |         |       |        |
                    | options-|------>| name   | 
                    | name    |       +--------+
                    +---------+
                         ^ 
+------------+           |
| Instance 2 |-----------+
+------------+      

现在,由于options是一个对象,如果你为它指定一个新属性,比如

instance1.object.name2 = 'bar';

您实际上正在访问Test.options。结果将是:

+------------+      +---------+       +--------+
| Instance 1 |----->| Test    |       | Object |
+------------+      |         |       |        |
                    | options-|------>| name   | 
                    | name    |       | name2  |
                    +---------+       +--------+
                         ^
+------------+           |
| Instance 2 |-----------+
+------------+ 

但是当您将新值分配给name时,将在该实例中创建新属性name。所以当你这样做时:

instance1.name = 'bar';

结果将是

+------------+      +---------+       +--------+
| Instance 1 |----->| Test    |       | Object |
|            |      |         |       |        |
| name       |      | options-+------>| name   | 
+------------+      | name    |       +--------+
                    +---------+
                         ^
+------------+           |
| Instance 2 |-----------+
+------------+      

如果不是仅仅访问或分配/ options的属性,而是为其分配了新值,就会发生同样的情况:

instance1.options = {name: 'another name'};

结果:

           +--------+
           | Object |
           |        |
           | name   |
           +--------+
                ^
+------------+  |   +---------+       +--------+
| Instance 1 |--+-->| Test    |       | Object |
|            |  |   |         |       |        |
| options----+--+   | options-|------>| name   | 
+------------+      | name    |       +--------+
                    +---------+
                         ^
+------------+           |
| Instance 2 |-----------+
+------------+

由于属性查找的工作方式,instance1.options将返回原型链中最近(最近)options属性的值。在我们为实例设置nameoptions后,它将返回这些值,而不是原型(Test)的值。

答案 2 :(得分:0)

我觉得你在这里有点困惑。

options: {
    name: 'foo'
},
name: 'foo'

当你定义它们,然后在你的Object.create()语句中使用时,属于原型,因此对于具有相同原型的所有对象都是相同的。

您看到name属性发生更改的原因是您在每个实例上创建了它(基本上覆盖了原型中定义的属性),方法是调用:

this.name = name;

对象属性不会发生的事情,因为您从未直接分配它。相反,它需要最后指定的值(在您的示例中为2)。

你写过:

this.options = {};
this.options.name = name;

init函数中 - options.name将在每个实例上被覆盖,就像你想要的那样。