文字实例创建行为各不相同

时间:2014-10-24 12:24:47

标签: javascript object object-literal

我有对象文字,我有另一个文字。 父实例正在设置值,但不是内部值。 我对这种行为感到困惑 为什么对象文字的行为不同?

这是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);

enter image description here

这不是一个重复的问题

  1. 我知道其他选择
  2. 我知道内部文字会覆盖我看到很多例子
  3. 我不知道为什么same behavior is not repeated for the parent object或换句话说

    为什么car.tires值正确显示而不是在我的示例中被覆盖

1 个答案:

答案 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一起使用的方式,我想他们可以设计一种语言来检测你是否在继承的seatsobject)上设置属性,然后复制将整个对象放入实例中。我的猜测是,这实际上会使系统变得不那么灵活和复杂。如果您希望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: - )