property getter does not reflect value of closure variable

Advertisements

I am confused by the way property getters interact with constructor closure.
Below is a minimal example:

function Ctor() {
  let closureX = 0
  
  Object.assign(this, {
    get publicX() { return closureX }
  })
  
  closureX++
  console.log(closureX)
}

let o = new Ctor()
console.log(o.publicX)

Why is o.publicX not changing when closureX does ?

>Solution :

It is simply because that’s what Object.assign does – it does not assign getters or setters, it assigns the values associated with the keys to the other object. MDN Docs already clarifies that getters will be invoked on the source and setters will be invoked on the target:

The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties, versus copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.

That last sentence is exactly what you are trying to do and it will not work.

You can verify this be checking its property descriptor and seeing that the new object did not inherit the getter from the source object, only the value that getter returns:

const object = Object.assign({}, {
    get publicX(){ return 3; }
});

console.log( object );

const definition = Object.getOwnPropertyDescriptor( object, 'publicX' )

console.log( definition ); // No getter defined, just a value

If you do want to accomplish this, the solution would probably be the old-fashioned Object.defineProperty to assign the getter:

function Ctor(){
  
  let closureX = 0;
  
  Object.defineProperty(this, 'publicX', {
      get(){ return closureX; }
  });
  
  closureX++;

}

const ctor = new Ctor();

console.log( ctor.publicX ); // It now returns the internal variable!

Leave a ReplyCancel reply