对于以下代码,为什么更新propB
中的myObj
?为什么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'));
答案 0 :(得分:11)
不使用Object.create
复制对象,而是创建一个新对象来继承传递的对象:
this.childObj { } -> myObj { propA: "", propB: [] }
现在,当您获得属性时,会在继承链中对其进行查找。由于无法在子对象中找到它,因此它会在myObj
中进行查找。通常这不是问题,因为设置对象属性无需使用继承链即可直接在对象本身上进行设置,因此:
this.childObj.propA += "test";
在propA
上查找myObj
,但在propA
上设置childObj
。但是,对于引用类型,您不会重写属性,因此:
this.childObj.propB.push(1);
在propB
中查找myObj
,然后推送到该位置,结果是:
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
中的数组。
答案 1 :(得分:3)
这是因为System.Web.HttpUtility.UrlEncode(string_to_encode)
成为了新创建的myObj
对象的原型(是通过Object.create创建它的结果。
由于您仅修改了test
的基础道具propB
(并且没有为childObj
分配新值),因此您仅修改了原型的道具。请在javascript中阅读有关inheritance的更多信息。
答案 2 :(得分:2)
通过使用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'));
答案 3 :(得分:1)
JavaScript继承与大多数其他语言不同。在使用var x = Object.create(someObj)
时,新对象x
实际上是空的(它没有其自身的属性),并且对其原型的引用是:单独的对象someObj
。
x
访问的任何属性或功能不能在此处解决的问题,将在someObj
中进行查找-甚至更高,如果someObj
也有原型对象,等等。
当继承的属性是可修改的对象时,事情可能会令人困惑,例如您的示例。如我们所见,尝试通过向其推送项目来修改数组x.propB
,实际上将修改someObj
中包含的继承数组。
我坚信在原型对象中包含可修改的对象(数组和常规对象)是不好的风格。相反,原型对象应包含仅功能和无数据,或者至少不包含不可修改的简单字符串,数字和布尔值之外的数据。
总结: