Oddity with getter, setter and console.dir in Chrome

A bit of pointless experimenting, writing a function to extend objects — I know we have class and super.

/**
 * Extend Object from Parent
 * @param {Object} parent - Parent to use as prototype of newly created object
 * @param {Object} child - Child who's prototype will be assigned the newly created object
 * @param {Object} optional - Optional object to merge with child's new prototype
 */
const extend = function (parent, child, optional = {}) {
  child.prototype = Object.assign(
    Object.create(parent.prototype,
      {
        constructor: {
          value: child,
          enumerable: false,
          writable: true,
          configurable: true
        },
        __super: {
          get: function () {
            return parent
          },
          set(...args) {
            if (args.length) parent.apply(this, args)
          },
          configurable: false,
          enumerable: false
        }
      }
    ),
    optional
  )
}

Testing

function Shape (colour, sides) {
  this.colour = colour
  this.sides = sides
}

Shape.prototype.duplicate = function () { console.log('duplicate') }

function Square (size, colour) {
  this.__super(colour, 4) // constructor stealing
  this.size = size
}

// extend shape with square
extend(Shape, Square, {
  // optional method to go on the prototype
  draw () {
    console.log('draw square')
  }
})

// Test
const sq1 = new Square(20, 'red')
console.log(sq1.__super) // => Square constructor FN
console.log(sq1.hasOwnProperty('__super')) // <-- false !!!
console.dir(sq1)

Output:
Square
  colour: "red"
  sides: 4
  size: 20
  __super: (...) <- why is __super here then?
  __proto__: Shape v
    draw: ƒ draw()
    constructor: ƒ Square(size, colour)
    __super: (...) <- and here
    get __super: ƒ get()
    set __super: ƒ set(...args)
    __proto__: v
      duplicate: ƒ ()
      constructor: ƒ Shape(colour, sides)
      __proto__: Object

Looking at the above output __super appear to be on the instance created by new Square(…) and on the prototype.

It doesn’t appear this way in Firefox. Is this a bit of behind the scenes Chrome optimization?

A bit puzzled. Thanks

Hm… is it a bug or a feature though? ^^ When specifying a value here it does not appear in console.dir(), only with a getter; this does indeed seem a bit arbitrary. The specs are not clear on that matter either, they just state that

The printer operation is implementation-defined.

So I don’t think there’s a particular reason for that, other than that it is how it is.

Not pointless at all, this is exactly the kind of experimenting that really gets you to know a language IMHO. :-)

1 Like

Thanks for looking into it m3g4p0p :+1:,

I will look into the specs, and also do a few tests with just basic getters and setters to see if there is some sort of pattern with this.

Cheers

1 Like

Just a quick follow up.

This issue was reported as a bug here
Console displays inherited getter as own property

I don’t know the authority of the person responding, but it seems to be intended behaviour with console.dir

The spec of console.dir [1] references the object formatting [2] which states “An object with optimally useful formatting is an implementation-specific, potentially-interactive representation of an object judged to be maximally useful and informative.”

While “x” is not an instance field of foo, but on the prototype, you are correct that “x” should technically not show up. Object.hasOwnProperty(foo, "x") will yield false. However, the information is useful, as invoking foo.x is allowed and will yield 3. This is especially prevalent in HTMLElements where various attributes are shown (like id) that live on the prototype.

Therefore, to keep the information useful, we opt to keep showing the information when running console.dir.

Not entirely sold on that. If ‘y’ is a standard property on foo’s prototype, we can still access it using foo.y — in logging it won’t show up on the instance

Anyway that seems to be the score :slight_smile:

Simple test

function Shape (sides) {
  this.sides = sides
}

Shape.prototype = {
  constructor: Shape,
  get numSides () {
    return this.sides
  },
  colour: 'red'
}

const sqr1 = new Shape(4)

console.dir(sqr1)
Output:
  Shape
    numSides: (...) <---
    sides: 4
    __proto__: v
      colour: "red"
      constructor: ƒ Shape(sides)
      numSides: (...) <---
      get numSides: ƒ numSides()
      __proto__: Object
    
console.log(sqr1.numSides) // 4
console.log(sqr1.colour) // red
1 Like

Ah interesting, a very pragmatic approach then. I would tend to agree with their reasoning regarding HTMLElements; and the getters are displayed in the same colour as the prototype after all. Anyway thx for that link! :-)

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.