0

I'm new to JS, so I'm trying to find a good pattern for having private fields with ECMAScript 6.

I'm using ES6's classes running on Node.js (latest version). I came up with the following snippet but I don't understand why a variable declared with let (which in my probably-incorrect-understanding has only block scope in ES6) will survive after the block has been executed:

class PrivateTest {
    constructor(aNumber) {
        let _aNumber = aNumber;

        //Privileged setter/getter with access to private _number:
        this.aNumber = function(value) {
            if (value !== undefined && (typeof value === typeof _aNumber)) {
                _aNumber = value;
            }
            else {
                return _aNumber;
            }
        }
    }
}

const privateTest = new PrivateTest(99);

console.log(privateTest.aNumber());
privateTest.aNumber(86);
console.log(privateTest.aNumber());
console.log(privateTest._aNumber); //Undefined.

// Just to try inheritance:
class PrivateTest2 extends PrivateTest {
}

const privateTest2 = new PrivateTest2(13);

console.log(privateTest2.aNumber());

The output is this:

99
86
undefined
13

From the code above, it seems that this private field can even be inherited.

So the questions are:

  • Am I doing right?
  • What's the life cycle of _number supposed to be?
nbloqs
  • 3,152
  • 1
  • 28
  • 49
  • 1
    Closures are unrelated to function or block scope. The function is defined in a scope where `_aNumber` exists, that's all that matters. *"it seems that this private field can even be inherited"* That really. There is no concept of "inheritance" for variables. What does get "inherited" is the function you are assigning to `this.aNumber`. And that function has access to a variable with name `_aNumber`. – Felix Kling May 17 '16 at 23:33
  • There is no such thing as "private fields" in ES6. You can use closure variables of course, but they're just variables. Btw, it doesn't make a difference here whether you declare them with `let`, `var`, or just as the constructor parameter. – Bergi May 18 '16 at 00:13
  • possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/q/111102/1048572) – Bergi May 18 '16 at 00:14
  • Hi @Bergi, I took a look to your link, and I thinkg that's a different question. I'm specifically asking about a pattern for emulating private fields in ES6 (I'm not interested at all in ES5 nor in prototyping OOP, just in using the new classes from ES6 in the most similar possible way to C++, Swift or Java classes). Thanks! – nbloqs May 18 '16 at 01:02
  • Also, my (probably incorrect) understanding is that in ES6 block-scoped variables are new and they can only be declared with "let": http://es6-features.org/#BlockScopedVariables – nbloqs May 18 '16 at 01:04
  • 1
    @nbloqs: The duplicate should answer your question "*I don't understand why a variable will survive after the block has been executed*". If you have more questions, you should probably post them separately. And no, it does not matter how the variable was declared and whether it is block- or function-scope (which in your example is the same anyway), closures work everywhere. – Bergi May 18 '16 at 01:09
  • 1
    @nbloqs: "*I'm interested in using the new classes from ES6 in the most similar possible way to C++, Swift or Java classes*" - please don't. Use them like JavaScript classes. Or like Python classes if you want. Local variables declared in the constructor and privileged methods are a perfectly fine approach if you need real privacy; otherwise just use properties that begin with an underscore. – Bergi May 18 '16 at 01:11
  • Hi @Bergi, thanks. That's a good answer for my problem. Python-like classes (but with real privacy) will be fine. Thank you. – nbloqs May 18 '16 at 01:15
  • 1
    Stop. JavaScript does not have private variables. – Mulan May 18 '16 at 03:48

1 Answers1

1

Your _aNumber (declared with let _aNumber = aNumber) doesn't exist outside of the class scope. You would get undefined if you tried to do console.log(_aNumber).

But JavaScript has something called closures that "freeze" variables inside of functions. This means that when you call the aNumber method of your class, the let variables still exist within that function.

Also, because JavaScript functions are first-class, assigning this.aNumber to a value is exactly equivalent to assigning this.aNumber to a function that returns a value, and then calling that function.

E.g.,

let a = 'foo';
let b = function() {
  return 'foo';
};

b();

console.log(a); // foo
console.log(b); // foo

It's tough to say if you are "doing it right", as I'm not exactly sure what you are going for. But learning more about closures and first-class functions might help you have a better grasp on the lifecycle of variables and the nature of variable assignments.

Himmel
  • 3,629
  • 6
  • 40
  • 77
  • Hi, thanks. Getting undefined from console.log(privateTest._aNumber) is exactly what I wanted, cause I'm looking for a pattern for private fields using the new ES6's classes. My question was specifically if that private "let declared variable" was going to continue existing after the constructor finished its execution, since I read here http://es6-features.org/#BlockScopedVariables that the variables declared with let are "block scoped". – nbloqs May 18 '16 at 01:08