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

时间:2018-11-29 07:57:31

标签: javascript

对于以下代码,为什么更新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'));

4 个答案:

答案 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中包含的继承数组。

我坚信在原型对象中包含可修改的对象(数组和常规对象)是不好的风格。相反,原型对象应包含仅功能无数据,或者至少不包含不可修改的简单字符串,数字和布尔值之外的数据。

总结:

  • 函数对于继承很有用,它们不可修改(您不能更改函数主体),并且在需要时仍可以覆盖/替换。
  • 数据成为所有继承者的共享数据,除非/直到他们通过重新分配将其覆盖,这本身就是负担。