最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How does the array property work in JS object - Stack Overflow

programmeradmin2浏览0评论

For the following code, why the propB of myObj is updated? And why test.childObj doesn't have the own property 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'));

For the following code, why the propB of myObj is updated? And why test.childObj doesn't have the own property 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'));

Share Improve this question edited Nov 29, 2018 at 8:26 falinsky 7,4284 gold badges34 silver badges58 bronze badges asked Nov 29, 2018 at 7:57 RickRick 3222 silver badges8 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 11

Using Object.create you do not copy an object, but you create a new object that inherits the passed one:

  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. 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. 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:

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

To resolve that, the childObj has to have its own propB array:

 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.

That is because myObj bees a prototype of newly created test object (caused by creating it via 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. Please read more about inheritance in javascript.

By using Object.create(myObj);, myObj bees the prototype of 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. 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.

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 e from, as myObj also have a prototype.

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. 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.

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.

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.

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 bees shared data by all inheritors, unless/until they override it by a re-assignment, which is a burden in itself.
发布评论

评论列表(0)

  1. 暂无评论