我有对象文字,我有另一个文字。 父实例正在设置值,但不是内部值。 我对这种行为感到困惑 为什么对象文字的行为不同?
这是http://jsfiddle.net/Lq6frf76/
var vehicle={
tires : 0,
seats : {
total :0
}
}
var Car = Object.create(vehicle);
Car.tires=4;
Car.seats.total = 4 ;
var bike = Object.create(vehicle);
bike.tires=2;
bike.seats.total = 2 ;
console.log(Car.tires); --->> it is not overwritten not consistent
console.log(Car.seats.total); -->> it is overwritten here
console.log(bike.tires);
console.log(bike.seats.total);
这不是一个重复的问题
我不知道为什么same behavior is not repeated for the parent object
或换句话说
为什么car.tires值正确显示而不是在我的示例中被覆盖
答案 0 :(得分:1)
修改:在最后添加更多内容并进行更正
我觉得我们需要在这里写下答案。如果这是一个糟糕的礼仪我会道歉(如果这是错误的答案)。请告诉我。
原型继承在javascript中的工作方式:
当您读取对象的属性时,可以说tires
对象的Car
属性,首先检查Car
是否具有该属性本身。这意味着,是否有tires
属性直接附加到Car
对象?换句话说,Car
是这样的:
{
tires: 0,
...
}
答案是肯定的。您可能认为Object.create()
执行此操作,类似于您在构造函数中可能执行的操作,即
function Vehice(t) {
this.tires = t;
...
};
var Car = new Vehicle(4);
所有Object.create()
所做的就是将您传递的对象放在它返回给您的对象的prototype
中。
所以在Object.create()
之后,你的对象看起来像这样
{
__proto__: //reference to vehicle
}
因此,当它没有找到直接附加到对象的tires
时,它会查看原型,在这种情况下是对您之前创建的vehicle
对象的引用。原型(vehicle
)确实具有tires
属性,因此它返回该值。
<强>校正强>
那么当你说Car.tires = 6
时会发生什么?当您将值写入对象属性时,情况会有所不同。 Javascript只查看对象本身是否具有要写入的属性。如果对象本身没有该属性,它首先检查原型链以确保该属性不是继承的 readonly 属性。如果不是,则在对象本身上创建该属性(只要将该属性写入对象是合法的)。所以现在你有一些看起来像这样的东西:
{
tires: 6,
__proto__: //reference to vehicle
}
结束更正
现在,当您读取tires
对象上的Car
属性时,它首先会看到tires
对象本身的Car
属性并返回该值,从不需要看看原型。
这就是为什么你可以在一辆车上设置tires
属性而不影响其他车辆的价值。
现在是seats.total
属性。当您从seats
属性中读取时,一切都像以前一样工作。 seats
对象本身没有Car
属性,因此它会查找具有它的原型。然后它检查seats
引用的对象,看它是否有一个total
属性直接附加到它,它确实如此,所以它只返回该值。
现在,当您想要写入total
属性时,事情再次发生了变化。声明如下:Car.seats.total = 4
。这里发生的是您在total
属性引用的对象上设置seats
属性。
Javascript首先必须找到seats
引用的对象。它通过检查它是否是Car
对象本身的属性来完成此操作。它不是,所以它检查原型,它找到seats
属性。现在它可以像我们之前看到的那样将total
属性写入seats
对象,但请注意,这发生在原型的seats
属性上,这是对{vehicle
的引用。 1}} bike
之前定义并由之共享的对象。
换句话说,javascript没有看到您正在写入Car
对象的属性,因此它不会在seats
对象上创建Car
属性并为其分配一个新对象,然后为该对象分配total
属性,并为其指定4
。
现在,当您尝试阅读bike
seats
属性时,javascript首先会查看bike
是否有seats
属性直接附加到该属性。它没有,所以它看起来是bike
的原型,它拥有它并返回修改后的vehicle.seats
对象。
我希望这可以澄清正在发生的事情并回答你的问题。如果有任何部分不清楚,请告诉我,如果我错了,我希望有人会纠正我!
附录:我认为来自传统OO语言的方式tires
适用于您期望发生的事情:您继承了初始值,但如果您更改它,你不希望它改变vehicle
的每个其他实例。
javascript这样做的方式非常经济。通过最初只有原型具有属性,如果你有一千个继承自vehicle
的对象,并且只有其中两个设置了tires
属性,那么你只用了三个{{1}的空间1}}而不是一千。
至于它与Number
一起使用的方式,我想他们可以设计一种语言来检测你是否在继承的seats
(object
)上设置属性,然后复制将整个对象放入实例中。我的猜测是,这实际上会使系统变得不那么灵活和复杂。如果您希望seats
拥有自己的Car
版本,您可以这样指定:
seats
或者像这样:
var car2 = Object.create(vehicle, {
seats: {
value: {
count: vehicle.seats.total
}
}
});
最后一个例子是否更清楚地说明了发生了什么?
对我来说,在这种情况下,显式的构造函数版本会更自然,但是使用javascript我们可以使用构造函数或`Object.create(),或者它们的各种组合来做我们需要的。
最终,每一套都分为两部分。首先,找到我们正在设置属性的对象;最后,设置属性。在最终var car2 = Object.create(vehicle);
car2.seats = { count: vehicle.seats.total }; //create a new object like the one attached to vehicle
之前的所有事情都是第一步:
.
表示将Car.seats.count = 10
引用的对象的count
属性设置为10.什么对象是Car.seats
?我们现在遵循读取属性的规则,而不是写一个。 Car.seats
没有Car
属性,因此请查看它是否继承了该属性。如果它没有,seats
将返回Car.seats
,并且尝试在undefined
上设置属性将引发错误。如果它确实继承了它,undefined
将从原型链的某个地方返回对象,在这种情况下是Car.seats
引用的对象。此对象具有vehicle
属性,因此只需将其设置为10.
count
表示将Car.tires = 4
引用的对象的tires
属性设置为4. Car
没有Car
属性,所以请确保我们可以创建一个然后再这样做。
我希望这能澄清事情。很抱歉写了这么多,但这样做真的有助于巩固这些概念。另外,我学到了一些我一直无视的ECMAScript 5: - )