Last active
August 29, 2015 14:14
-
-
Save timdream/379bdd1d26d807556bba to your computer and use it in GitHub Desktop.
Private method/property with WeakMap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/** | |
* Demonstration for creating private variable/method in JavaScript | |
* constrcutors, with WeakMap trick. | |
* | |
* The idea here is to create two WeakMaps to link a public instance and | |
* a private instance, and two shorthand query function to query between two. | |
* | |
* Both instances can therefore have their own methods respectively. | |
* An "apply()" apply trick is also demonstrated in privateMethod2() but | |
* it's too confusing thus not recommended. | |
* "pubThis" and "privThis" should be more understandable in this setup. | |
* | |
* Note that even though this is shown passing "window" as exporting object, | |
* it can surely be the module.exports in CommonJS environment. | |
* The point here is to have your own closure to encapsulate the WeakMaps. | |
* | |
* I expect, if anyone will ever use this setup, most of the methods will be | |
* in the PrivateClass and PublicClass will simply be a wrapper/pointers | |
* to the methods & properties. It would be easier to keep most of the lines | |
* pointing to the same "this". | |
*/ | |
(function(exports) { | |
var publicPrivateInstanceMap = new WeakMap(); | |
var _p = publicPrivateInstanceMap.get.bind(publicPrivateInstanceMap); | |
var privatePublicInstanceMap = new WeakMap(); | |
var _rp = privatePublicInstanceMap.get.bind(privatePublicInstanceMap); | |
var PrivateClass = function() { | |
}; | |
PrivateClass.prototype.linkWithPublicInstance = function(publicInstance) { | |
publicPrivateInstanceMap.set(publicInstance, this); | |
privatePublicInstanceMap.set(this, publicInstance); | |
}; | |
PrivateClass.prototype.privateProperty = 'myPrivateProperty'; | |
PrivateClass.prototype.privateMethod = function() { | |
var val = this.privateProperty; | |
// Get pubic instance and set public property. | |
var pubThis = _rp(this); | |
pubThis.publicProperty = 'bar'; | |
}; | |
PrivateClass.prototype.privateMethod2 = function() { | |
// Call ourselve with public instance instead. | |
if (this instanceof PrivateClass) { | |
return this.privateMethod.apply(_rp(this), arguments); | |
} | |
// "this" is is the public instance beyond this point. | |
this.publicProperty = 'baz'; | |
}; | |
var PublicClass = function PublicClass() { | |
var privateInstance = new PrivateClass(); | |
privateInstance.linkWithPublicInstance(this); | |
}; | |
PublicClass.prototype.publicProperty = 'foo'; | |
PublicClass.prototype.publicMethod = function() { | |
// Get private instance. | |
var privThis = _p(this); | |
privThis.privateProperty = 'newPrivateValue'; | |
// Call private method. | |
privThis.privateMethod(); | |
}; | |
// Only export the PublicClass | |
exports.PublicClass = PublicClass; | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
we use a similar way in https://github.com/mozilla-b2g/gaia/blob/793773bb2944b42a85dd160049e605cbd880c4da/apps/sms/js/subject_composer.js#L96-L111 :)