-1

Private variables are variables that are visible only to the class to which they belong. It is a common opinion that there are no strict private variables in JS (except for the new fields like this.#property). Can anyone kindly explain why the variable 'boy' bellow cannot be considered to be a private one?

class Forrest {
  constructor() {
    let boy = "Bobby"
    this.getBoy = function() {
      console.log(boy)
    }
  }
}

const f = new Forrest()
f.getBoy() // Bobby
Maksym Dudyk
  • 1,082
  • 14
  • 16
  • 8
    The `let boy` is in a closure, so sure looks pretty private to me. Closures are private - *mostly* https://stackoverflow.com/a/59424277 – CertainPerformance Feb 19 '21 at 16:22
  • There's experimental support for private fields - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields – Kunal Mukherjee Feb 19 '21 at 16:22
  • 3
    @KunalMukherjee Which OP mentioned in the question – CertainPerformance Feb 19 '21 at 16:22
  • JavaScript only recently has classes. Without classes the private/public visibility question doesn't make sense. There are only variables, and their scope. – OrangeDog Feb 19 '21 at 16:24
  • @OrangeDog - The pattern above was common with just constructor functions, too. There's nothing in the question (other than `let`) that wouldn't be virtually identical with an ES5 constructor function. – T.J. Crowder Feb 19 '21 at 16:26
  • 1
    There's nothing non-private about `boy` in your example. In any OO language I've ever seen, a public getter can access any private variable; it's an *extremely* common pattern in Java, for example. – Pointy Feb 19 '21 at 16:26
  • 2
    As CertainPerformance and Pointy have already said, that `boy` is pretty darned private. :-) Note that regardless of how you feel about the closure approach above, though, JavaScript [will have true private fields](https://github.com/tc39/proposal-class-fields) very, very soon. It's implemented in most major engines and likely to hit the spec this year. – T.J. Crowder Feb 19 '21 at 16:27
  • 1
    "*Private variables are variables that are visible only to the class to which they belong.*" given this definition, why do you believe `boy` is visible *to the class*? – VLAZ Feb 19 '21 at 16:47
  • @VLAZ Because we can access it via method getBoy, defined in this class. – Maksym Dudyk Feb 19 '21 at 19:12
  • @MaksymDudyk because it's private *to the constructor*. But if you declare a normal method, then that variable is not visible there. Ergo, it's not visible *to the class*. – VLAZ Feb 19 '21 at 19:34
  • @VLAZ If we are looking for a variable only 'visible to the class', we would pick up a static variable. – Maksym Dudyk Feb 19 '21 at 19:49

1 Answers1

3

I haven't heard people claim that boy in your example isn't private. Quite the opposite, it's private to the constructor and getBoy. Nothing else (including nothing else in that class) can access it. But either way, I suppose that might be in the "opinion-based" realm.

Stepping out of that realm: Regardless of someone may feel about the closure approach shown in the question, JavaScript will have true private fields very, very soon. It's implemented in most major engines and likely to hit the spec this year. Your example with private fields looks like this:

class Forrest {
    #boy = "Bobby";

    getBoy() {
        console.log(this.#boy);
    }
}

const f = new Forrest();
f.getBoy() // Bobby

Or if we set it from a constructor parameter:

class Forrest {
    #boy;
    constructor(boy) {
        this.#boy = boy;
    }

    getBoy() {
        console.log(this.#boy);
    }
}

const f = new Forrest("Bobby");
f.getBoy() // Bobby

Those will run on up-to-date versions of Chromium-based browsers. Safari and Firefox won't be much longer.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you, T.J. These 'true private fields' which are comming, do you think we'd better call them 'protected' not 'private', since we can access them from inherited classes like this: class Forrest { #boy = "Bobby"; getBoy() { console.log(this.#boy); } } class Holt extends Forrest { getIt() { return this.getBoy(); } } var h = new Holt() h.getIt(); // Bobby – Maksym Dudyk Feb 19 '21 at 17:50
  • @MaksymDudyk - No. The *field* is private. What you're doing there is providing a **public** accessor for the field. That accessor is public (you don't even need `Holt`, you could just it outside any class), but the *field* is private. If the field were protected, you could use it via `this.#boy` in `Holt`, which you can't. – T.J. Crowder Feb 19 '21 at 17:54