1

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

19
  • 3
    Any prototype chain can have the Array prototype in it. 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...) 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 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() Commented Mar 8 at 4:30
  • 3
    Please post a minimal reproducible example that shows how you assigned myrecordset. Commented Mar 8 at 5:07

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.