3

Using the # syntax we are able now to create private properties in ES6 classes like this:

class Person {
    #name;
    constructor(name) {
        this.#name = name;
    }
    getName() { return this.#name; }
}

let ron = new Person('ron')
ron.#name // undefined
ron.getName(); // ron

Previously, in ES5, private properties can be hardly 'faked' in the following way:

function Person(name) {
  var name = name;
  this.getName = function() {
    return name;
  }
}
(new Person('ron')).name // undefined
(new Person('ron')).getName() // ron

the above version is using the fact 'var' will not belong to 'this' of instances of Person. And so using the power of 'closure' getName has access to 'name'. However, the problem with this is that this.getName() is not a part of the prototype chain so in order to add getName to the prototype we will have to do:

Person.prototype.getName = function() { return this.getName(); }

which is confusing and is smelling pretty bad.

another option is to do: (using ES6 symbols and still not using classes)

function Person(name) {
  const nameSymbol = Symbol();
  this[nameSymbol] = name;
  this.getName = function() {
    return this[nameSymbol];
  }
}

but still not solving the problem that getName is not a part of the prototype. Another problem is that using Object.getOwnPropertySymbols, this 'fake' private member is accessible.

another es5 option will be to use the 'Revleaing module pattern' and exposing a publicAPI like this:

const myEs5Module = (function () { 
  var _name = 'yos';
  function getName() {
    return _name;
  }
  const publicAPI = { getname };
  return publicAPI;
})();

but that is not a class or a constructor function, it's more like a module.

So I would like to understand if '#' syntax for private properties in ES6 classes is syntactic sugar and can be polyfilled in some way for function lovers like myself.

BTW: I read posts like the following: Private properties in JavaScript ES6 classes and still feel unsatisfied. also NOTE: I am not looking for ES6 modules / babel solution

Eva Cohen
  • 375
  • 3
  • 18
  • everything to do with classes in JS is 'syntactic sugar' – andy mccullough Dec 21 '20 at 08:58
  • The private properties are polyfiable, but the thing is that if you log the class instance in debugger, you might see even the private properties of it – Akxe Dec 21 '20 at 09:00
  • @andymccullough - That used to be true, before private properties and methods, but it isn't anymore. – T.J. Crowder Dec 21 '20 at 09:01
  • 1
    @andymccullough [Are ES6 classes just syntactic sugar for the prototypal pattern in Javascript?](https://stackoverflow.com/q/36419713) – adiga Dec 21 '20 at 09:05

1 Answers1

4

Are ES6 class private properties just syntactic sugar?

No. They're a fundamental addition to how objects work at an internal level. Private fields (as they're called) are held in new slots in the object that didn't exist before the proposal and are not accessible in other ways.

So I would like to understand if '#' syntax for private properties in ES6 classes is syntactic sugar and can be polyfilled in some way for function lovers like myself.

You can't use private properties without class syntax. (Future proposals may change that.) Instead, you'd have to keep doing what you're doing (the closure solution) or use a WeakMap only your functions have access to keyed by the object the properties relate to.

You've done your own closure examples, so here's your Person class using the WeakMap approach instead of private properties:

const Person = (() => {
    const names = new WeakMap();
    function Person(name) {
        names.set(this, name);
    }
    Person.prototype.getName = function getName() {
        return names.get(this);
    };
    return Person;
})();

let ron = new Person("ron")
console.log(ron.name);      // undefined
console.log(ron.getName()); // "ron"
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • FWIW, I go into private fields (and some of the other `class` features that are likely to advance to Stage 4 ["finished'} this year) in detail in my recent book *JavaScript: The New Toys* in Chapter 18. Links in my profile if you're interested. – T.J. Crowder Dec 21 '20 at 09:17
  • 1
    This is a super helpful answer and a fantastic bonus to my understanding. Thank you very much. – Eva Cohen Dec 21 '20 at 12:32
  • I feel a need to further clarify something. I see you used WeakMap with 'this' as the key, and 'name' as the value. so that every instance will have its own 'name' as needed. But How about: const Person = (() => { let _name = null; function Person(name) { _name = name; } Person.prototype.getName = function getName() { return _name; }; return Person; }); const PersonFactory = function(name) { const PersonMaker = Person(); return new PersonMaker(name); } – Eva Cohen Dec 21 '20 at 12:52
  • It was not an IIFE I suggested but simply a function expression. I am sorry or the code formatting that might got you confused. I tested it and it does create different Mary and Joe. – Eva Cohen Dec 21 '20 at 14:08
  • 1
    @EvaCohen - Sorry, read too fast. But that's *much* more complicated than you need, and it creates a whole new `Person` (and `Person.prototype`) each time you create an instance, reusing nothing. You're better off just using the `Person` function from the second code block in your question and closing over the parameter directly. – T.J. Crowder Dec 21 '20 at 14:34