1

I am trying to have a private property inside my class. I have a class called Person and an instance of that class: person declared with let person = new Person('name1').

I would like to save the name in person's properties. I could simply do:

class Person {

  constructor(name) {

    this.name = name;

  }

}

But I also want to perform some actions when changing this value, so I use a Setter:

class Person {

  set name() {

    // some actions 

  }

  constructor(name) { }

}

But then how do I save the name? I would have to have another property for example _name that would be used to save the actual value

class Person {

  set name(newName) {

    // some actions
    return this._name;

  }

  set name(newName) {

    this._name = name;
    // some actions

  }

  constructor(name) {

    this._name = name;

  }

}

The problem is that _name can be accessed outside with person._name.

Is there a way to make it not accessible from outside?


I took inspiration from this answer (which doesn't use a getter and setter) and tried to enclose _name when defining the getter and setter. The following code doesn't work:

class Person {

    constructor(name) {

        var _name = name;
        Object.defineProperties(this, {
            "name": {
                 "get": () => { return _name; },
                 "set": () => { _name = name; }
            }
        });

    }
}
Ivan
  • 34,531
  • 8
  • 55
  • 100
  • "*The problem is that `_name` can be accessed outside with `person._name`.*" - Is that really a problem? Every sensible developer will notice the leading underscore and by convention not use this property when the `.name` getter is available anyway that gets you the exact same value. – Bergi Sep 07 '18 at 14:25
  • "*The following code doesn't work:*" - it does. What is the error you are getting, how are you using that `Person` class? – Bergi Sep 07 '18 at 14:26
  • @Bergi: we all know that "doesn't work" tells us little. But the code as described doesn't allow you to set the name. A side-effect in that `set` call will still run, but the internal property won't change because it's missing the parameter, as NicholasTower pointed out. – Scott Sauyet Sep 07 '18 at 14:32
  • @Bergi *Is that really a problem?*, I thought it was... Having both `_name` and `name` as properties seemed like an issue to me. – Ivan Sep 07 '18 at 14:36
  • @ScottSauyet, thank you, I have removed my answer. I totally forgot that the initial goal was to use a setter to perform some actions when setting the value. – Ivan Sep 07 '18 at 14:42
  • In your code, with Nicholas Tower's tweak, you will not have a `_name` property. That will be captured in the closure. This is as close as you're likely to get to private properties in JS until the new feature is added. – Scott Sauyet Sep 07 '18 at 14:43
  • @ScottSauyet, I understand that the getter can return the enclosed value held by `_name`. However, I find it hard to understand how the Setter can redefine `_name`'s value. Are private properties actually planned as future features? – Ivan Sep 07 '18 at 15:17
  • @Ivan: I believe there is at least one TC39 proposal for private properties. I don't know what stage they're in or how likely they are to proceed. As to how that variable is changeable, the constructor function creates a closure, and any functions inside that closure, such as `get name` and `set name` have access to the variables inside that closure, including `_name`. They can both access and mutate it. For more details, search for "javascript closure". – Scott Sauyet Sep 07 '18 at 15:28

1 Answers1

3

"set": () => { _name = name; }

You just have a small mistake here. Should be:

"set": (newName) => { _name = newName; }
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98