简体   繁体   English

数组属性如何在JS对象中工作

[英]How does the array property work in JS object

For the following code, why the propB of myObj is updated? 对于以下代码,为什么myObjpropB更新? And why test.childObj doesn't have the own property propB ? 为什么test.childObj没有自己的属性propB

 var myObj = { propA: '', propB: [] } var fatherObj = { childObj: null, init: function() { this.childObj = Object.create(myObj); this.childObj.propA = 'A'; this.childObj.propB.push(2); } } var test = Object.create(fatherObj); test.init(); console.log(myObj.propB.length); console.log(test.childObj.hasOwnProperty('propA')); console.log(test.childObj.hasOwnProperty('propB')); 

Using Object.create you do not copy an object, but you create a new object that inherits the passed one: 使用Object.create不复制对象,但是创建了一个继承传递的对象的新对象:

  this.childObj { } ->  myObj { propA: "", propB: [] }

Now when you get a property, it gets looked up in the inheritance chain. 现在当你得到一个属性时,它会在继承链中被查找。 As it can't be found in the child object, it gets looked up in myObj . 因为它无法在子对象中找到,所以它会在myObj查找。 That is usually not a problem, as setting an objects property directly sets it on the object itself without using the inheritance chain, therefore this: 这通常不是问题,因为设置对象属性直接将其设置在对象本身而不使用继承链,因此:

  this.childObj.propA += "test";

looks up propA on myObj but sets propA on the childObj . myObj上查找propA但在propA上设置childObj With reference types however, you do not rewrite the property, therefore this: 但是,对于引用类型,您不会重写属性,因此:

  this.childObj.propB.push(1);

looks up propB in myObj , and pushes to that, the result is: myObj查找propB ,并推送到那个,结果是:

 this.childObj { propA: "test" } ->  myObj { propA: "", propB: [1] }

To resolve that, the childObj has to have its own propB array: 要解决这个问题,childObj必须有自己的propB数组:

 this.childObj.propB = this.childObj.propB.slice();

That results in: 这导致:

 this.childObj { propA: "test", propB: [1] } ->  myObj { propA: "", propB: [1] }

and now pushing to propB pushes to the array in childObj . 现在推到propB推到在阵列childObj

That is because myObj becomes a prototype of newly created test object (caused by creating it via Object.create . 这是因为myObj成为新创建的test对象的原型(通过Object.create创建它)。

Due to you just modify underlying prop propB of childObj (and not assign the new value like for propA ) you only modify the prop of prototype. 由于你刚刚修改底层支柱propBchildObj (而不是像指派为新值propA ),你只修改原型的道具。 Please read more about inheritance in javascript. 请阅读有关javascript 继承的更多信息。

By using Object.create(myObj); 通过使用Object.create(myObj); , myObj becomes the prototype of childObj . myObj成为childObj的原型。 If a property is not found in an object and is found in the prototype, the one from the prototype is used. 如果在对象中找不到属性并且在原型中找到该属性,则使用原型中的属性。 Also note that hasOwnProperty tells if the objects owns the property itself, and will return false if it exists only in the prototype and not in the object. 另请注意, hasOwnProperty告诉对象是否拥有属性本身,如果它仅存在于原型中而不存在于对象中,则返回false。 By assigning directly a property on an object, you set it on the object, not on the prototype, but when you modify the property propB with push, the property is not found directly in childObject, so you modify the prototype. 通过直接在对象上分配属性,可以在对象上设置它,而不是在原型上,但是当您使用push修改属性propB时,不会直接在childObject中找到该属性,因此您可以修改原型。

You have to be careful with that, as all objects created this way will share the same prototype object and by modifying one, you will modify it for all instances. 你必须要小心,因为以这种方式创建的所有对象将共享相同的原型对象,并且通过修改一个,您将为所有实例修改它。

You have also to be extra careful because it can be tricky to know in javascript where in the prototype chain your property come from, as myObj also have a prototype. 你还要格外小心,因为在javascript中知道你的属性来自原型链的位置可能很棘手,因为myObj也有原型。

 var myObj = { propA: '', propB: [] } var fatherObj = { childObj: null, init: function() { this.childObj = Object.create(myObj); this.childObj.propA = 'A'; this.childObj.propB.push(2); } } var test = Object.create(fatherObj); test.init(); console.log('test: ', test); console.log('test prototype: ', test.__proto__); console.log('test.childObj: ', test.childObj); console.log('test.childObj prototype: ', test.childObj.__proto__); console.log(test.childObj.hasOwnProperty('propA')); console.log(test.childObj.hasOwnProperty('propB')); 

Javascript inheritance does not work like in most other languages. Javascript继承不像大多数其他语言那样工作。 When using var x = Object.create(someObj) , the new object x is actually empty (it has no properties of its own) along with a reference to its prototype: the separate object someObj . 当使用var x = Object.create(someObj) ,新对象x实际上是空的(它没有自己的属性)以及对其原型的引用:单独的对象someObj

Any property or function that you then try to access from x which does not resolve there, will be looked up in someObj - or even higher up, if someObj also has a prototype object, etc. 您尝试从x访问的任何属性函数都将在someObj查找 - 或者甚至更高,如果someObj也有原型对象等。

Things can get confusing when inherited properties are modifiable objects , as in your example. 当继承的属性是可修改的对象时 ,事情会变得混乱,如在您的示例中。 As we have seen, trying to modify the array x.propB by pushing an item to it, will actually modify the inherited array contained in someObj . 正如我们所看到的,尝试通过x.propB推送项来修改数组x.propB ,实际上将修改someObj包含的继承数组。

I'm strongly convinced that it is bad style to have modifiable objects (both arrays and regular objects) in prototype objects. 我坚信在原型对象中拥有可修改的对象(包括数组和常规对象)是不好的方式 Instead, prototype objects should contain only functions and no data , or at least no data beyond simple strings, numbers and booleans which are not modifiable. 相反,原型对象应该包含函数 而不包含数据 ,或者至少不包含不可修改的简单字符串,数字和布尔值之外的数据。

To summarize: 总结一下:

  • Functions are useful to inherit, they are not modifiable (you can't change the function body), and can still be overridden/replaced if needed. 函数对于继承很有用,它们不可修改(您无法更改函数体),并且如果需要仍可以覆盖/替换。
  • Data becomes shared data by all inheritors, unless/until they override it by a re-assignment, which is a burden in itself. 数据成为所有继承者的共享数据,除非/直到它们通过重新分配覆盖它,这本身就是一种负担。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM