javascriptarraysobjectprototype

array.prototype is being applied to a non-array object (?)


I have a library with the following addition for Array types -

Array.prototype.top = function() {
    return (this.length > 0) ? this[this.length-1] : null;
    }

It seems to be applied to non-Array objects - e.g.,

for (key in myrecordset) {
    alert(key);                // will iterate and alert "top";
    } 

      

In the debugger console:

> myrecordset.length
< undefined
> typeof myrecordset
< 'object'
> myrecordset instanceof(Array)
< false
> myrecordset['top']
< f() {
      return (this.length ...
      }

So, what the ? The object is not a javascript array (ie, no length, not an instance of, ...) but the Array.prototype.top seems to have been applied?

Note: in addition, trying to follow the prototype chain I get

> myrecordset.constructor()
< {}
    [[ Prototype ]]: Object

SCOPE: screen shot with myrecordsetenter image description here


Solution

  • To properly extend a prototype you should make the new props non enumerable. In your case you could be interested in a fix that runs after including the problematic code, it will convert all enumerable props to non enumerable:

    Array.prototype.top = function () {
        return this.length ? this[this.length-1] : null;
    }
    
    function makeNonEnumerable(obj){
      const props = Object.getOwnPropertyDescriptors(obj);
      for(const name in props){
        const desc = props[name]
        if(desc.enumerable){
          desc.enumerable = false;
          Object.defineProperty(obj, name, desc);
        }
      }    
    }
    
    makeNonEnumerable(Array.prototype);
    
    console.log([1,2,3].top()); // 3
    
    class RecordSet {
        constructor(...items) {
            Object.assign(this, items);
            Object.assign(this, Array.prototype);
        }
    }
    
    const myrecordset = new RecordSet({a:1}, {b:2});
    
    console.log(myrecordset); // "0": .. "1":