Define static properties and prototype properties with the class syntax

Rick Waldron waldron.rick at gmail.com
Sat Dec 13 10:44:11 PST 2014


On Sat Dec 13 2014 at 4:54:55 AM Glen Huang <curvedmark at gmail.com> wrote:

> But allowing getter & setter already makes it dangerous:
>
> let _bar = {}
> class Foo {
>         static get bar() { return _bar; }
> }
>
> Objects that have Foo.prototype in the prototype chain can do "this.bar.a
> = 1", and the change won’t be shadowed.
>

The accessor property "bar" is _not_ created on Foo.prototype, it's created
on Foo itself and would not be found on `this`.

In ES5, the example above would look like this:

var _bar = {};
var Foo = function Foo() {}

Object.defineProperty(Foo, "bar", {
  get: function() {
    return _bar;
  }
});



>
> I found myself looking for a way to define static properties because I
> want to do this:
>
> function Menu(options) {
>         this.options = Object.assign({}, Menu.defaults, options);
> }
> Menu.defaults = { hidden: false };
>
>
  class Menu {
    constructor(options) {
       this.options = Object.assign({}, Menu.defaults, options);
    }
    static get defaults() {
      return Object.freeze({ hidden: false });
    }
  }

This has the benefit of preventing unwanted tampering with `Menu. defaults`
by ensuring that the only way to modify defaults is by explicitly providing
them via  `new Menu({ my opts })`. The property can be _read_ as
`Menu.defaults` but assignment to `Menu.defaults` or attempts to change
values or add properties will throw.




> I want to expose the defaults property so it can be modified by users.
> This pattern is very ubiquitous in es5. I wonder if the class syntax could
> allow this pattern to be carried to es6?
>

ES6 is done, but this is something that I also want to revisit for ES7
(should be a year following ES6). In the meantime, it's not too painful to
address this use case by doing this:

  class Menu {
    constructor(options) {
       this.options = Object.assign({}, Menu.defaults, options);
    }
  }

  Menu.defaults = { hidden: true };

Though I'm not sure what the benefit is to allowing any code access to an
the unprotected defaults. If you and I are working on a large system using
this class, with potentially many Menu components on the same page and I
change the defaults, all other code can no longer trust the defaults to be
correct. That said, it's not always as simple as creating a closure with
the defaults so they're not exposed at all—exposing them is certainly
useful for testing, and/or verifying correct, expected initial state with
some baseline shape.

Rick
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20141213/4dc4bc90/attachment.html>


More information about the es-discuss mailing list