Search code examples
javascriptinheritanceprototypees6-class

ES6 Class prototypes - type resolution


Here's the use case

Ive extended the Array class:

class ExtendedArray extends Array {
  constructor(...args) {
    super(...args);

    this.test = 10;
  }

  testTwo() {
  }
}

Now i have some methods where i want to map my ExtendedArray instance and return another instance of ExtendedArray which works out of the box.

However in other situations i want to map over the ExtendedArray but return an actual Array instance and not my ExtendedArray. In this situation i thought i could walk up the __proto__ chain and call .constructor.

This is when i noticed some odd behavior which i didn't expect.

Based on the class above i would have expected a hierarchy like this

/*
  ExtendedArray
    test: 10
    __proto__: Object
        testTwo: () {}
      __proto__: Array
        forEach
        ...
        __proto__: Object
            ...
*/

However i get one like this:

/*
  ExtendedArray
    test: 10
    __proto__: Array -- Different
        constructor: class ExtendedArray
        testTwo: () {}
      __proto__: Array(0) -- Different
        constructor: f Array()
        forEach
        ...
        __proto__: Object
            ...
*/

Can anyone explain what the difference between Array and Array(0) is in the prototypes type. Also why is the first prototype an instance of Array when its constructor is the ExtendedArray class and when its created based on the methods in the class body definition. I would have expected that to ether be an Object or ExtendedArray in type?

Any help understanding this behavior would be great.

I've attempted to research this and found information explaining where the different class fields and methods go in the resulting object, but not how the types of prototype objects are resolved.


Solution

  • The "types" shown in the debugger are pretty meaningless. They're just trying to be helpful on instances, but usually cause confusion on prototype objects. They are also different between browsers, and often change between devtools versions.

    All those values are simply objects, and their structure and prototype chain is exactly what you are expecting.

    What is the difference between Array and Array(0)?

    The Array.prototype object has a .length = 0 property. Your ExtendedArray.prototype has not.

    Why is the first prototype an instance of Array when its constructor is the ExtendedArray class. I would have expected that to ether be an Object or ExtendedArray in type?

    It's not an ExtendedArray instance - it doesn't inherit from ExtendedArray.prototype (because it is ExtendedArray.prototype). It's just an object like {constructor: ExtendedArray}.

    It does however inherit from Array.prototype, so that's what is shown as the "type".