admin管理员组

文章数量:1405754

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 myrecordset

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 myrecordset

Share Improve this question edited Mar 8 at 5:23 Nick Parsons 51.2k6 gold badges57 silver badges78 bronze badges asked Mar 8 at 4:04 Chrys GChrys G 11110 bronze badges 19
  • 3 Any prototype chain can have the Array prototype in it. – Pointy Commented Mar 8 at 4:06
  • You did not show what myrecordset is. Please, answer a simple question: What happens if you call myrecordset['top']()? (If lenght is undefined...) – Sergey A Kryukov Commented Mar 8 at 4:19
  • myrecordset['top']() returns null the object myrecordset: from debugger::scope object with three keys '0' '1' and 'top' [[prototype]]: Object – Chrys G Commented Mar 8 at 4:23
  • 1 Use Object.getPrototypeOf(myrecordset); or just log myrecordset and follow the [[Prototype]] internal slots to follow the prototype chain, not .constructor() – Nick Parsons Commented Mar 8 at 4:30
  • 3 Please post a minimal reproducible example that shows how you assigned myrecordset. – Barmar Commented Mar 8 at 5:07
 |  Show 14 more comments

2 Answers 2

Reset to default 1

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

There are many ways that an object may get a property that is equal to top. The screenshot proves that myrecordset has a top property that is not an inherited property, but is an "own" property. This means it got copied there.

Here is one possible scenario that could have happened:

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

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("top" in myrecordset); // true
console.log(myrecordset.length); // undefined
console.log(typeof myrecordset); // object
console.log(myrecordset instanceof Array); // false
console.log(myrecordset.top === Array.prototype.top); // true
console.log(myrecordset); // "0": .. "1": .. "top": ..

One way to possibly prevent this, is to define top as a non-enumerable property on the Array prototype:

Object.defineProperty(Array.prototype, "top", {
    configurable: true,
    writable: true,
    value() {
        return this.length ? this[this.length-1] : null;
    }
});

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("top" in myrecordset); // false
console.log(myrecordset.top); // undefined
console.log(myrecordset); // "0": .. "1": ..

本文标签: javascriptarrayprototype is being applied to a nonarray object ()Stack Overflow