继承和对象。在Javascript中创建

继承和对象。在Javascript中创建,javascript,prototypal-inheritance,object-create,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 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;
    }
var测试={
选项:{
姓名:“富”
},
名称:“foo”,
init:函数(名称){
this.name=名称;
this.options.name=名称;
}
};
var dict={};
对于(变量i=0;i<3;i++){
var obj=Object.create(测试);
对象初始(i);
dict[i]=obj;
}
我不明白为什么dict[X].options.name中的所有属性都在对象dict中 具有相同的值(2)和dict[X]中的属性。名称具有不同的值

它似乎与通过引用传递值有关

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

一个粗略的图像应该是这样的

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

alert(Test.options== dict[0].options);
问题很清楚:

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

因此,
Test
将成为新对象的原型。所有实例都引用相同的原型,并且由于
选项
是一个对象,因此它们也共享对该原型的引用

关系如下所示:

+------------+      +---------+       +--------+
| 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 |-----------+
+------------+      
如果您不只是访问或分配/to
options
的属性,而是为其分配了一个新值,则会发生同样的情况:

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

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

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

我认为您在这里有点困惑

options: {
    name: 'foo'
},
name: 'foo'
当您定义它们并在
Object.create()
语句中使用时,它们属于原型,因此对于具有相同原型的所有对象都是相同的

您看到
name
属性更改的原因是您通过调用以下命令在每个实例上创建了它(基本上覆盖了原型中定义的实例):

this.name = name;
对象属性不会发生的某些情况,因为您从未直接指定它。取而代之的是最后一个赋值(在你的例子中是2)

你有没有写过:

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

在您的
init
函数中-options.name将在每个实例上被覆盖,并且与您想要的一样。

我认为您需要调用
对象。create(Test.prototype)
@Tejs:
Test.prototype
是一个空对象。@Tejs。不,Object.create就是这样工作的。
.prototype
是对
新的
语法的一种破解。我认为这并不能回答为什么
名称
在所有实例中都不同,而
选项。名称
没有。但是也许我弄错了。我会提供我的答案。