3

我使用原型继承这个代码段:属性不同

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 

为什么?

+1

刚刚创建SubType'的'一个新的实例。尝试 'var instance2 = instance1' – Cyval

+1

数组和对象通过引用传递,而对于基本类型(字符串,数字等)引用是值,[related](http://stackoverflow.com/questions/518000/IS-JavaScript的一个通按引用-或通按值的语言) – maioman

回答

1

当你写

instance1.x = 2; 

您添加了一个名为xinstance1新属性。

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

当您参考

instance1.x 

对象的自身属性instance1.x优先于原型的财产instance1.__proto__.x。我们说xinstance1阴影xinstance1.__proto__

当JavaScript评估instance1.x时,它会在向上移动原型链之前检查自己的属性instance1。因此,您所看到的属性值为instance1.x

但是,当你写

instance1.colors 

对象instance1不具有自己的财产被称为colors。因此,JavaScript会查看其原型。它找到instance1.__proto__.colors并返回其当前值。

当你写

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>

4

问题是这里:

SubType.prototype = new SuperType(); 

由于SuperType构造放.colors阵列在物体上,并且由于物体被用作SubType.prototype,即.colors阵列所有SubType实例之间共享。

相反,建立在继承,但SubType构造函数中调用它不调用构造函数。

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

.x没有同样的问题的原因是,数字是不可变的,所以当你试图修改它,一个新的x被直接您正在使用,而不是在对象上创建突变.prototype

0

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

当您使用= 2时,您将替换该变量的值,因此其他变量仍可指向原始值。