Skip to content

Instantly share code, notes, and snippets.

@greim
Last active May 23, 2018 02:54
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save greim/44e54c2f23eab955bb73b31426e96d6c to your computer and use it in GitHub Desktop.
Save greim/44e54c2f23eab955bb73b31426e96d6c to your computer and use it in GitHub Desktop.

Private members in ES6 classes

"Let's create an ES6 class!" you say. "Let's give it a private variable x."

class Foo {
  constructor(x) {
    this.x = x;
  }
  getX() {
    return this.x;
  }
}

"Please." I respond, rolling my eyes. "That x variable isn't REALLY private. It's right there for the whole world to read and write!"

"We'll just prepended it with an underscore," you retort. "People will never use it because it's ugly and that underscore will scare them off!"

class Foo {
  constructor(x) {
    this._x = x;
  }
  getX() {
    return this._x;
  }
}

"It is ugly," I concede, furrowing my brow and looking down as I swirl the coffee in the bottom of my glass while taking on an air of troubled superiority, "but it still isn't private, and they WILL use it."

"Well then we can just fly it in under the radar," you counter. "We'll make it not be enumerable. Nobody will suspect it's there!"

class Foo {
  constructor(x) {
    Object.defineProperty(this, 'x', {
      value: x,
      enumerable: false,
    });
  }
  getX() {
    return this.x;
  }
}

[Setting my glass down] "That is, until they read the source code," I reply, deadpan.

"We'll keep it truly private, then," you chortle nervously, looking at others in the room for support, all of whom refuse to make eye contact. "We'll just keep everything hidden inside the constructor's closure. Problem solved!"

class Foo {
  constructor(x) {
    this.getX = () => x;
  }
}

"But now," I argue, raising my palm to my forehead, "every instance of that class has a duplicate copy of that function. Not only is it less efficient, but it breaks expectations. People expect it to exist on the prototype, and when it doesn't, they'll be confused and blame you!"

"Okay then," you say, grasping at straws, "we'll store it outside the class in a map, keyed by instances, where nobody can reach it, maybe?"

const __ = new Map();

class Foo {
  constructor(x) {
    __.set(this, { x });
  }
  getX() {
    var { x } = __.get(this);
    return x;
  }
}

"But now you have a memory leak," I refute triumphantly, smelling victory. "That map keeps STRONG references to every class instance you put in it, thus retaining it in memory by creating a referential backpath to a GC root, well after the app has finished using it!"

"Hmmm..." you wonder, stroking your chin and narrowing your eyes. "Then we'll just make it a WeakMap."

const __ = new WeakMap();

class Foo {
  constructor(x) {
    __.set(this, { x });
  }
  getX() {
    var { x } = __.get(this);
    return x;
  }
}

Me: Has no rebuttal. Sweats profusely.

@gitnik
Copy link

gitnik commented Apr 13, 2016

Another option is using Symbols:

const privateVar = Symbol('privateVar');

export default class Foo {
    constructor(x) {
        this[privateVar] = x;
    }

   getX() {
        return this[privateVar];       
   }
}

@Wildhoney
Copy link

Symbol === Symbol; // true
Symbol('x') === Symbol('x'); // false

Thus:

const privateVar = Symbol('abc');

However symbols are still accessible with Object.getOwnPropertySymbols.

@phpnode
Copy link

phpnode commented Apr 13, 2016

Symbols are accessible that way but it's hard to tie the symbol to its meaning. If you get two symbols back, which is which? In practice this is so hard that most people won't do it. Symbols will always be faster than weakmaps and let you have 'protected' as a visibility as well as private (just export the symbol and you can use it elsewhere within your project).

@greim
Copy link
Author

greim commented Apr 15, 2016

Good points about using symbols. I guess it boils down to whether you want a deterrent or a guarantee.

@antonia0912
Copy link

I found this is very useful for developers, so can we translate this article in Chinese and share it with more Chinese developers?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment