Skip to content

Instantly share code, notes, and snippets.

@juandopazo
Last active September 10, 2018 07:59
Show Gist options
  • Save juandopazo/2901426 to your computer and use it in GitHub Desktop.
Save juandopazo/2901426 to your computer and use it in GitHub Desktop.
Privates and WeakMaps
// Based on a gist by @rwaldron
// https://gist.github.com/2897761
function privatize() {
var map = new WeakMap();
return function private(obj) {
var data = map.get(obj);
if (!data) {
map.set(obj, data = {});
}
return data;
};
}
var Person = (function () {
var private = privatize();
function Person(name) {
private(this).name = name;
}
Person.prototype.say = function (msg) {
return private(this).name + ' says: ' + msg;
};
return Person;
}());
@rauschma
Copy link

rauschma commented Jun 9, 2012

Why not just a global function private?

@juandopazo
Copy link
Author

Because that would leak the data to anyone with a reference to the instance.

@demian85
Copy link

demian85 commented Jun 9, 2012

Donde hay un resumen de las nuevas features de ES6 que ya se puedan usar en Node/V8?

@juandopazo
Copy link
Author

Esa es una buena pregunta. Hay que ver en cada versión de Node qué build de V8 usaron. Es bastante molesto. Y peor aún, hay cosas que están detrás de flags en V8 y por ende no están en Node. Otras están detrás de flags en node como node --harmony-proxies.

@juandopazo
Copy link
Author

As a side note, this is "class private". Which means you can access private data of other members of the same class. For example:

Person.prototype.stealName = function (someGuy) {
  return private(someGuy).name; // works if someGuy instanceof Person
};

@tomasdev
Copy link

Why not just:

var Person = (function () {

  var private = {};

  function Person(name) {
    private.name = name;
  }
  Person.prototype.say = function (msg) {
    return private.name + ' says: ' + msg;
  };

  return Person;

}());

@juandopazo
Copy link
Author

Because that would share the private data with all instances of Person. It would be the same as:

var Person = (function () {
  var _name;

  function Person(name) {
    _name = name;
  }
  Person.prototype.say = function (msg) {
    return _name + ' says: ' + msg;
  };

  return Person;
}());

var bob = new Person('Bob');
var peter = new Person('Peter');
bob.say('Hi!'); // Peter says: Hi!

That means it needs to be a map. And it needs to be a WeakMap so that the private record is GC'ed when the class instance is GC'ed.

@papiro
Copy link

papiro commented Sep 3, 2016

why not:

const _ = new WeakMap()
const private = (instance) => {
  return _.get(instance)
}

class Person {
  constructor (name) {
    private(this).name = name
  }
  say (msg) {
    return private(this).name + 'says: ' + msg
  }
}

?

EDIT:

Actually, private should be defined as const private = (instance) => _.has(instance) ? _.get(instance) : _.set(instance)

@praveeno
Copy link

praveeno commented May 18, 2018

hey @juandopazo, i didn't get this
Because that would leak the data to anyone with a reference to the instance.

can you elaborate more

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