2

In JavaScript, lazy getters can improve performance.
Some explanation can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters

How do I get lazy getters working in strict mode?
This JavaScript code does not work:

'use strict'

function Obj(x) {
    this.x = x
}

Obj.prototype = {
    get y() {
    delete this.y
    return this.y = this.x + 1
  }
}

let obj = new Obj(100)

console.log('100 + 1 = ', obj.y)

It gives the following error: TypeError: setting getter-only property "y"

If I remove 'use strict', then the code works fine.
How do I get this to work in strict mode?

Hendrik Jan
  • 4,396
  • 8
  • 39
  • 75
  • 1
    @JonasW. you'll probably have to wrap it in an IIFE if you run it in the console to let the strict mode directive take effect. It would also work in a script. – Bergi Apr 07 '18 at 19:19

1 Answers1

2

The delete keyword doesn't do what you think - it only deletes own properties. There is however an important difference between Obj.prototype.y and obj.j.

Using delete this.y in a getter used on obj doesn't delete anything as obj doesn't have a y property.

Afterwards, you try to assign to obj.y in the getter. This does not work - there already is an inherited y accessor property, so it will call the setter of that instead of creating a new property. You can check by inspecting obj after having used the getter - it doesn't actually have a y: 101 property now, using obj.y will run the getter again.

The difference between strict and sloppy mode is just that the missing setter will either cause an exception or simply be ignored.

To fix this, remove the delete statement - it doesn't work, and you don't want to delete the Obj.prototype.y getter anyway, it should continue to work on other Obj instances. Instead you will want to shadow it with an own y property for obj. You can use Object.defineProperty(this, "y", {value: this.x+1}) for that.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Couple of years later now but still... Thanks for the detailed answer, however... let's just say for whatever reason he does want to delete the y getter and have y set permanently at 101 (or whatever). Regardless of the practical implications, how is OP's code different to the example he linked to on Mozilla's site? (Im' struggling with a similar issue right now). – DavidT Sep 02 '20 at 18:53
  • Actually... on further review, your answer on the other linked ('already has answers') SO question seems to answer my above question. The actual code on Mozilla's site (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters) works when `notifier` is static but not when not. ie. delete and reassign the prototype property but not `this` on the instance. I'm tempted to delete my comments now, but maybe keeping them here might help someone else in the future. Either way, thanks! – DavidT Sep 02 '20 at 19:03
  • @DavidT The MDN example uses a plain object literal and no inheritance, while the OP uses the object with the getter as a prototype for his `obj` on which he tries to access `y`. It would have worked when accessing `Obj.prototype.y` (although `x` is undefined which makes it result in `NaN`) or when writing code with `delete Obj.prototype.y` (which would have broken `.y` for other `new Obj` instances of course). – Bergi Sep 02 '20 at 19:06
  • Thanks again. Ok I think that makes sense. I'm trying to do this inside a class. Admittedly I'm still struggling sometimes to get my head around JS's prototype OOP vs what I'm more familiar with: traditional class OOP (and I understand the recent `class` syntax in JS is just sugar). I'm confused why the MDN example works when it's static in the class but not in an instantiated object, though I think now I understand it only really makes sense if specifically made the object's property not the class's (prototype's). Right? – DavidT Sep 02 '20 at 19:37
  • @DavidT yes, and unless you subclass your `class` you'd normally access the static property on the (class) object that it was defined on, not something inheriting for it. – Bergi Sep 02 '20 at 20:22