Javascript 使用 Object.create 和属性指针未从原型中取消引用
Javascript use of Object.create and properties pointers not being dereferenced from prototype
谁能解释一下当我 o1.set('bar');
时发生了什么?我想知道为什么此时也设置了 o2.name
,而当我设置 o2.set('fox');
时却没有发生同样的情况,我的意思是,o1.name
仍然是 bar
。
为什么 o1.name 和 o2.name 指向同一个对象,即使我更改了旧值 (foo
) 但当我更改 o2.name?
var Person = {
name: "foo",
get: function get() {
return this.name;
},
set: function set(sur) {
this.name = sur;
}
},
o1 = Person,
o2 = Object.create(o1);
// true "foo" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o1.set('bar');
// true "bar" "bar"
console.log(o1.name === o2.name, o1.get(), o2.get());
o2.set('fox');
// false "bar" "fox"
console.log(o1.name === o2.name, o1.get(), o2.get());
下面可以看到另一个行为。这里的不同之处在于,我什至为 o1
对象扩展了 Person 原型。
var Person = {
name: "foo",
get: function get() {
return this.name;
},
set: function set(sur) {
this.name = sur;
}
},
o1 = Object.create(Person),
o2 = Object.create(Person);
// true "foo" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o1.set('bar');
// false "bar" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o2.set('fox');
// false "bar" "fox"
console.log(o1.name === o2.name, o1.get(), o2.get());
对象 o2
从其原型链继承 "name" 属性。但是,一旦 属性 被设置,对象本身就会受到影响。
换句话说,在设置对象 属性 时不参考原型链。 属性 更新(或添加)总是直接在目标对象上。仅在检查 属性 个值时才参考原型链。
This 在调用o2.set("fox");
set()
函数时本身就找到了原型。但是,该调用中 this
的值是 o2
,而不是 o1
,因此对 this.name
的赋值会直接影响 o2
。
答案可以在 Eric Elliot 的好书“Programming JavaScript Applications”中找到,我认为这可以在这里找到问题 Delegate Prototypes。
埃里克说:
"在 JavaScript 中,对象具有对委托原型的内部引用。当查询对象的 属性 或方法时,JavaScript 引擎首先检查对象。如果该对象上不存在键,它将检查委托原型,依此类推原型链。原型链通常在对象原型处结束。"
并完成解释:
"原型上的属性就像默认值一样。当您在实例上设置它们时,实例值仅会覆盖该实例的值。"
换句话说,我知道调用 o1.get()
时我正在更改原型,而 o2
对象正在扩展它。但是,当我调用 o2.get()
时,我不再更改原型而是 o2
实例。这就是为什么在那之后 o1.name
上的任何更改现在都与 o2.name
分离。
谁能解释一下当我 o1.set('bar');
时发生了什么?我想知道为什么此时也设置了 o2.name
,而当我设置 o2.set('fox');
时却没有发生同样的情况,我的意思是,o1.name
仍然是 bar
。
为什么 o1.name 和 o2.name 指向同一个对象,即使我更改了旧值 (foo
) 但当我更改 o2.name?
var Person = {
name: "foo",
get: function get() {
return this.name;
},
set: function set(sur) {
this.name = sur;
}
},
o1 = Person,
o2 = Object.create(o1);
// true "foo" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o1.set('bar');
// true "bar" "bar"
console.log(o1.name === o2.name, o1.get(), o2.get());
o2.set('fox');
// false "bar" "fox"
console.log(o1.name === o2.name, o1.get(), o2.get());
下面可以看到另一个行为。这里的不同之处在于,我什至为 o1
对象扩展了 Person 原型。
var Person = {
name: "foo",
get: function get() {
return this.name;
},
set: function set(sur) {
this.name = sur;
}
},
o1 = Object.create(Person),
o2 = Object.create(Person);
// true "foo" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o1.set('bar');
// false "bar" "foo"
console.log(o1.name === o2.name, o1.get(), o2.get());
o2.set('fox');
// false "bar" "fox"
console.log(o1.name === o2.name, o1.get(), o2.get());
对象 o2
从其原型链继承 "name" 属性。但是,一旦 属性 被设置,对象本身就会受到影响。
换句话说,在设置对象 属性 时不参考原型链。 属性 更新(或添加)总是直接在目标对象上。仅在检查 属性 个值时才参考原型链。
This 在调用o2.set("fox");
set()
函数时本身就找到了原型。但是,该调用中 this
的值是 o2
,而不是 o1
,因此对 this.name
的赋值会直接影响 o2
。
答案可以在 Eric Elliot 的好书“Programming JavaScript Applications”中找到,我认为这可以在这里找到问题 Delegate Prototypes。
埃里克说:
"在 JavaScript 中,对象具有对委托原型的内部引用。当查询对象的 属性 或方法时,JavaScript 引擎首先检查对象。如果该对象上不存在键,它将检查委托原型,依此类推原型链。原型链通常在对象原型处结束。"
并完成解释:
"原型上的属性就像默认值一样。当您在实例上设置它们时,实例值仅会覆盖该实例的值。"
换句话说,我知道调用 o1.get()
时我正在更改原型,而 o2
对象正在扩展它。但是,当我调用 o2.get()
时,我不再更改原型而是 o2
实例。这就是为什么在那之后 o1.name
上的任何更改现在都与 o2.name
分离。