Skip to content

Instantly share code, notes, and snippets.

@greim
Last active May 23, 2018 02:54
Show Gist options
  • 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.

@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