0

Is it possible to make a private 'set' in js?

class Player{
    constructor(nickname){
        this._nickname = nickname;
    }
    get _nickname(){
        return value;
    }
    set _nickname(value){
        this.nickname = value;
    }
}
Joe
  • 383
  • 1
  • 3
  • 15
  • 4
    I'm curious as why you want to make them private. The whole point of getters and setters are to be public to access private data. Also, value doesn't exist in get – Andrew Li Sep 04 '16 at 16:47
  • 2
    OP - You forget. ES2015 classes cannot have private anything. As it's just syntax sugar for normal prototypes inheritance. – evolutionxbox Sep 04 '16 at 16:47
  • Suppose I wanted to initialize some field in the constructor, but prevent anyone from changing it, but still able to 'get' it? – Joe Sep 04 '16 at 16:53
  • Then remove the set function. – Andrew Li Sep 04 '16 at 16:55
  • @Andrew but then I get an error: 'Cannot set property _nickname of # which has only a getter' – Joe Sep 04 '16 at 16:58
  • see this video https://vimeo.com/97419177 at 38 minutes. – Gatsbill Sep 04 '16 at 17:04
  • Change the accessors to `nickname` which get and set `this._nickname`. – evolutionxbox Sep 04 '16 at 17:11
  • @evolutionxbox, I know I can, but I wanted it clean and elegant – Joe Sep 04 '16 at 17:14
  • Unfortunately you might want to steer clear of es2015 classes then. As they don't allow the kind of privacy you want, not without creating circular accessors. – evolutionxbox Sep 04 '16 at 17:15
  • yeah I guess it also explains why I didn't find anything about it on the web. At least now I won't waste any more of my time searching for an answer. Thnks – Joe Sep 04 '16 at 17:18
  • 3
    Is this a dup of https://stackoverflow.com/questions/22156326/private-properties-in-javascript-es6-classes ? – loganfsmyth Sep 04 '16 at 17:24
  • This is not the generic "private property" question. The OP presumably wants a setter which he can use within class methods, but which is not visible from outside. It's a rather obscure use case, but different from private properties in general. –  Sep 04 '16 at 18:38
  • @torazaburo in what way is it obscure? – Joe Sep 04 '16 at 19:00
  • It is obscure in that, as mentioned by another commenter, normally setters are used as a way to provide access from the outside. –  Sep 04 '16 at 19:10
  • but I want to set it only once and only by constructor. what do you suggest? writable:false? – Joe Sep 04 '16 at 19:26

1 Answers1

0

You can use a proxy:

class Player{
  constructor(nickname) { this._nickname = nickname; }
  get nickname()        { return this._nickname; }
  set nickname(value)   { this._nickname = value; }
}

function makePlayer(nickname) {
  const player = new Player(nickname);

  return new Proxy(player, {

    set(target, property, value, receiver) {
      if (property === 'nickname' || property === '_nickname') 
        throw "Can't set nickname or _nickname!";
      target[property] = value;
    },

    get(target, property, receiver) {
      console.log("property is", property);
      if (property === '_nickname') 
        throw "Can't get _nickname!";
      return target[property];
    }

  });
}

const player = makePlayer("Bob");
console.log(player.nickname);
player.nickname = "Sally";  // Can't set nickname or _nickname!

The set nickname(value) in the definition allows you to say this.nickname = "Donald"; within the class methods, which is what I assume you want to do, and have the setter handle the setting. The proxy intercepts gets and sets on nickname and _nickname and blocks them as necessary. You can export only makePlayer and keep Player private in order to prevent the bad guys from instantiating Player directly and circumventing your elaborate privacy mechanisms.