[英]How does the array property work in JS object
对于以下代码,为什么myObj
的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'));
使用Object.create
不复制对象,但是创建了一个继承传递的对象的新对象:
this.childObj { } -> myObj { propA: "", propB: [] }
现在当你得到一个属性时,它会在继承链中被查找。 因为它无法在子对象中找到,所以它会在myObj
查找。 这通常不是问题,因为设置对象属性直接将其设置在对象本身而不使用继承链,因此:
this.childObj.propA += "test";
在myObj
上查找propA
但在propA
上设置childObj
。 但是,对于引用类型,您不会重写属性,因此:
this.childObj.propB.push(1);
在myObj
查找propB
,并推送到那个,结果是:
this.childObj { propA: "test" } -> myObj { propA: "", propB: [1] }
要解决这个问题,childObj必须有自己的propB
数组:
this.childObj.propB = this.childObj.propB.slice();
这导致:
this.childObj { propA: "test", propB: [1] } -> myObj { propA: "", propB: [1] }
现在推到propB
推到在阵列childObj
。
这是因为myObj
成为新创建的test
对象的原型(通过Object.create创建它)。
由于你刚刚修改底层支柱propB
的childObj
(而不是像指派为新值propA
),你只修改原型的道具。 请阅读有关javascript 继承的更多信息。
通过使用Object.create(myObj);
, myObj
成为childObj
的原型。 如果在对象中找不到属性并且在原型中找到该属性,则使用原型中的属性。 另请注意, hasOwnProperty
告诉对象是否拥有属性本身,如果它仅存在于原型中而不存在于对象中,则返回false。 通过直接在对象上分配属性,可以在对象上设置它,而不是在原型上,但是当您使用push修改属性propB时,不会直接在childObject中找到该属性,因此您可以修改原型。
你必须要小心,因为以这种方式创建的所有对象将共享相同的原型对象,并且通过修改一个,您将为所有实例修改它。
你还要格外小心,因为在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继承不像大多数其他语言那样工作。 当使用var x = Object.create(someObj)
,新对象x
实际上是空的(它没有自己的属性)以及对其原型的引用:单独的对象someObj
。
您尝试从x
访问的任何属性或函数都将在someObj
查找 - 或者甚至更高,如果someObj
也有原型对象等。
当继承的属性是可修改的对象时 ,事情会变得混乱,如在您的示例中。 正如我们所看到的,尝试通过x.propB
推送项来修改数组x.propB
,实际上将修改someObj
包含的继承数组。
我坚信在原型对象中拥有可修改的对象(包括数组和常规对象)是不好的方式 。 相反,原型对象应该只包含函数 而不包含数据 ,或者至少不包含不可修改的简单字符串,数字和布尔值之外的数据。
总结一下:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.