原型上的属性受到不同的影响

Properties on a prototype being affected differently

我在此代码段中使用了原型继承:

function SuperType() {
  this.colors = ["red", "blue", "green"];
  this.x = 1;
}

function SubType() {}
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
instance1.x = 2;
//alert(instance1.colors); // "red,blue,green,black"
//alert(instance1.x); // 2

var instance2 = new SubType();
alert(instance2.colors); // "red,blue,green,black"
alert(instance2.x); // 1

我希望输出是

"red,blue,green"
1

"red,blue,green,black"
2

但我得到:

"red,blue,green,black"
1

为什么?

问题出在这里:

SubType.prototype = new SuperType();

因为SuperType构造函数把.colors数组放在对象上,又因为对象作为SubType.prototype,所以.colors 数组在所有 SubType 个实例之间共享。

相反,在设置继承时不要调用构造函数,而是 doSubType 构造函数中调用它。

function SubType() {
    SuperType.apply(this, arguments);
}
SubType.prototype = Object.create(SuperType.prototype);

.x 没有同样问题的原因是数字不可变,因此当您尝试修改它时,会直接在对象上创建一个新的 x重新使用而不是改变 .prototype.

当您 运行 .push("black") 时,您正在使用一种修改对象(颜色列表)的方法;所以指向该对象的所有变量都会看到变化。

当您使用 = 2 时,您正在替换那个变量的值,因此其他变量仍然可以指向原始值。

写的时候

instance1.x = 2;

您正在向 instance1 添加一个名为 x 的新 属性。

instance1的原型,你可以用instance1.__proto__查找,不受影响。 instance1.__proto__.x的值还是1。

当你参考

instance1.x

对象自身的 属性 instance1.x 优先于原型的 属性 instance1.__proto__.x。我们说 x on instance1 shadows x on instance1.__proto__.

当 JavaScript 计算 instance1.x 时,它会在向上移动原型链之前检查 instance1 自己的属性。所以,自己的值属性instance1.x就是你看到的

但是当你写的时候

instance1.colors

对象 instance1 没有自己的 属性 称为 colors。所以,JavaScript看它的原型。它找到 instance1.__proto__.colors 和 returns 其当前值。

你写的时候

instance1.colors.push("black");

您没有向 instance1 添加新的 属性。您只是修改了数组 instance1.__proto__.colors。具有相同原型的所有对象都将看到相同的 colors 值,除非它们具有遮蔽 colors.

的 属性

在下面的代码片段中,我创建了第三个对象 c,它定义了一个名为 colors 的自己的 属性,它隐藏了原型的 属性 c.__proto__.colors.

var c = new SubType();
c.colors = [ 'orange', 'purple' ];

自身的值 属性 c.colors 与原型的 属性 c.__proto__.colors 的数组不同。没有自己的 属性 colors 的对象将继续看到原型的 colors.

的值

function SuperType() {
    this.colors = ["red", "blue", "green"];
    this.x = 1;
}
function SubType() {}
SubType.prototype = new SuperType();

var a = new SubType();
a.colors.push("black");
a.x = 2;
message('a.colors: ' + a.colors.join(', '));  // red, blue, green, black (prototype's colors)
message('a.x: ' + a.x);                       // 2 (own property x)
message('a.__proto__.x: ' + a.__proto__.x);   // 1 (prototype's x)

var b = new SubType();
message('b.colors: ' + b.colors.join(', '));  // red, blue, green, black (prototype's colors)
message('b.x: ' + b.x);                       // 1 (prototype's x)

var c = new SubType();
// Make an own property, colors, that shadows the prototype's property.
c.colors = [ 'orange', 'purple' ];
message('c.colors: ' + c.colors.join(', '));  // orange, purple (own property colors)
message('b.colors: ' + b.colors.join(', '));  // red, blue, green, black (prototype's colors)
message('a.colors: ' + a.colors.join(', '));  // red, blue, green, black (prototype's colors)


function message(line) {
  document.getElementById('messageBox').innerHTML += line + '<br>';
}
body {
  font-family: sans-serif;
}
<div id="messageBox"></div>