1

Ok I am killing my brain here I have an array

var myArray = ['Bob', 'Sue', 'Jim'];
myArray.__proto__ = new Entity();

//Entity looks something like this
Entity = function(){
   this.isChanged = false;
   this.add = function(newPerson){
      alert(this.length); //alerts with 3
      alert(JSON.stringify(this)); //alerts a {}
      this.push(newPerson); 
      this.isChanged = true;

  }
}

push does not exist on an object but its obviously an array as per the alert returning a 3.

very curious how to access my array that seems to be wrapped by an object thanks to my proto

B_Manx
  • 27
  • 5

2 Answers2

2

how to access my array that seems to be wrapped by an object thanks to my __proto__

It is not wrapped - it just lost it's identity due to your modification of __proto__. The array now inherits from your new Entity instance instead of from Array.prototype.

If you want to call Array methods on it, you will have to do it using .call:

Array.prototype.push.call(this, newPerson);

However, your implementation of inheritance is questionable anyway. Even if you use an array object and mutate its [[prototype]], you rather should be doing

var myArray = new Entitiy(['Bob', 'Sue', 'Jim']);

// Entity looks like this
function Entity(arr) {
    if (!Array.isArray(arr)) {
        arr = [];
        // maybe:
        // arr.push.apply(arr, arguments);
    }
    arr.__proto__ = Entity.prototype;
    arr.isChanged = false;
    return arr;
}
Entity.prototype = Object.create(Array.prototype);
Entity.prototype.constructor = Entity;
Entity.prototype.add = function(newPerson) {
    alert(this.length); //alerts with 3
    alert(JSON.stringify(this)); //alerts a ["Bob","Sue","Jim"]
    this.push(newPerson);
    this.isChanged = true;
};
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Very Nice! Thank you! this is exactly what I was looking for. If I had posted the full code you would see that I was attempting to use Entity for both objects and arrays. Some of the properties really did not need to be inherited by the array so in an attempt to be more simplistic things got really weird lol. – B_Manx Oct 19 '14 at 12:06
1

The array isn't wrapped, it's no longer an array! __proto__ is a depricated getter/setter pair to access an objects internal [[Prototype]]. Since you assign a value the setter is used and you simply overwrite its complete prototype with an instance of Entity. That's why push() (and all others: pop(), splice(), ... ) doesn't exist any longer.

Why alert(this.length);works ? length is not a property of Array.prototype but an own property of each Array instance. So it's not overwritten/removed by changing the prototype, your "thing" still has a length. You can check that with following:

console.log(Object.getOwnPropertyNames(myArray)); // --> ['0', '1', '2', 'length']

Of course you can access the properties of your "thing", e.g. console.log(myArray[1]) // --> 'Sue'or assign new properties, but you have to use object-methods for it. So if inside Entity() instead of this.push(newPerson) you use this[this.length] = newPerson it will work.

Reference for __proto__ here.

Martin Ernst
  • 3,199
  • 1
  • 12
  • 12
  • The MDN is possibly out of date, \_\_proto\_\_ in some form is being codified into the es 6 spec http://stackoverflow.com/questions/13839115/does-ecmascript-6-support-a-mutable-proto-property – Jared Smith Oct 18 '14 at 14:59
  • @JaredSmith: Note that this answer is from 2012, ES6 has moved on. Mutating the [[prototype]] should be done with [`Reflect.setPrototypeOf`](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect.setprototypeof), `__proto__` is still deprecated (but codified - standardised - for web legacy compatibility in [Annex B](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-additional-ecmascript-features-for-web-browsers)) – Bergi Oct 18 '14 at 15:11
  • Thanks guys! I have dropped __proto__ from my toolbag and now using the new version. – B_Manx Oct 19 '14 at 12:09