我刚刚开始搞乱Javascript继承,并且不能让我围绕这个:#/ p>
如果我运行此代码:
function Foo(y) {
this.y = y;
}
Foo.prototype.x = 1;
var Bar1 = new Foo(2);
var Bar2 = new Foo(3);
我希望在内存中有以下“结构”:
我在图形中搞砸了,Bar2的属性“y”显然值为“3”
幸运的是,我可以通过运行此代码来确认:
console.log("Prototype - x: ", Foo.prototype.x, " y: ", Foo.prototype.y);
console.log("Bar1 - x: ", Bar1.x, " y: ", Bar1.y);
console.log("Bar2 - x: ", Bar2.x, " y: ", Bar2.y);
打印:
Prototype - x: 1 y: undefined
Bar1 - x: 1 y: 2
Bar2 - x: 1 y: 3
如果我错了,请纠正我,但是当我尝试访问Bar1和Bar2对象中的属性x时,正如那些对象不是localy有一个名为x的属性,我得到了来自原型链中下一个对象的属性;即他们在“_ proto _”属性中存储的引用。
现在是我迷路的时候,因为如果我在那段代码之后改变x的值,就像这样:
Bar1.x = 10;
我现在跑
console.log("Prototype - x: ", Foo.prototype.x, " y: ", Foo.prototype.y);
console.log("Bar1 - x: ", Bar1.x, " y: ", Bar1.y);
console.log("Bar2 - x: ", Bar2.x, " y: ", Bar2.y);
我得到的是
Prototype - x: 1 y: undefined
Bar1 - x: 10 y: 2
Bar2 - x: 1 y: 3
而不是我期望的:
Prototype - x: 10 y: undefined
Bar1 - x: 10 y: 2
Bar2 - x: 10 y: 3
那时我只能通过假设每个对象都创建了Foo.prototype对象的副本来解释,但是如果我运行这个
console.log(Object.is(Foo.prototype, Bar1.__proto__), Object.is(Bar1.__proto__, Bar2.__proto__));
我得到true true
,因此Bar1,Bar2都访问同一个对象。
为什么Bar1会为x显示不同的值,如果它们都是从同一个对象获取它的话?
答案 0 :(得分:3)
这一行:
Bar1.x = 10;
不会更改原型中x
的值。相反,它会为x
创建一个新属性(Bar1
),并为其分配10
的值。因此,Bar1
不再从原型中继承x
,因为它现在拥有自己的属性x
。
Bar2
仍然存在,这就是它仍然与原型值匹配的原因。
答案 1 :(得分:2)
非常简单:
分配始终在对象本身上创建或更新属性。
赋值永远不会影响原型链,即使该属性存在于链的某个位置(*)。
只有读取属性遍历原型链,停在实际拥有该属性的对象上。
如果您对技术问题感兴趣,请查看PutValue
definition in the specification。
(*):但是,如果原型链中存在该属性,则可能会对分配产生影响。如果属性存在且只读(不可写),则赋值不会 创建一个新属性。例如:
> var obj = Object.create(Object.create({}, {x: {value: 10}}));
undefined
> obj.x
10
> obj.x = 100;
100
> obj.x
10
答案 2 :(得分:0)
关于Bar1
和Bar2
如何获得x
的值,你是对的。但是当你分配Bar1.x = 10
时,它会崩溃。
尝试访问x
时,它首先从对象本身开始,然后向下爬行。我们假设您尝试访问Bar1.z
。查找看起来像这样:
Bar1.z
Bar1.prototype.z
Bar1.__proto__.z
,即Foo.prototype
Object.prototype.z
(因为所有对象都自然地继承自Object
z
,返回undefined
通过分配Bar1.x
,您可以有效地隐藏Bar1.__proto__.x
的值,因为它将首先出现在查找中。