diff options
Diffstat (limited to 'node_modules/private/README.md')
-rw-r--r-- | node_modules/private/README.md | 245 |
1 files changed, 0 insertions, 245 deletions
diff --git a/node_modules/private/README.md b/node_modules/private/README.md deleted file mode 100644 index 493077b..0000000 --- a/node_modules/private/README.md +++ /dev/null @@ -1,245 +0,0 @@ -# private [](https://travis-ci.org/benjamn/private) [](https://greenkeeper.io/) - -A general-purpose utility for associating truly private state with any JavaScript object. - -Installation ---- - -From NPM: - - npm install private - -From GitHub: - - cd path/to/node_modules - git clone git://github.com/benjamn/private.git - cd private - npm install . - -Usage ---- -**Get or create a secret object associated with any (non-frozen) object:** -```js -var getSecret = require("private").makeAccessor(); -var obj = Object.create(null); // any kind of object works -getSecret(obj).totallySafeProperty = "p455w0rd"; - -console.log(Object.keys(obj)); // [] -console.log(Object.getOwnPropertyNames(obj)); // [] -console.log(getSecret(obj)); // { totallySafeProperty: "p455w0rd" } -``` -Now, only code that has a reference to both `getSecret` and `obj` can possibly access `.totallySafeProperty`. - -*Importantly, no global references to the secret object are retained by the `private` package, so as soon as `obj` gets garbage collected, the secret will be reclaimed as well. In other words, you don't have to worry about memory leaks.* - -**Create a unique property name that cannot be enumerated or guessed:** -```js -var secretKey = require("private").makeUniqueKey(); -var obj = Object.create(null); // any kind of object works - -Object.defineProperty(obj, secretKey, { - value: { totallySafeProperty: "p455w0rd" }, - enumerable: false // optional; non-enumerability is the default -}); - -Object.defineProperty(obj, "nonEnumerableProperty", { - value: "anyone can guess my name", - enumerable: false -}); - -console.log(obj[secretKey].totallySafeProperty); // p455w0rd -console.log(obj.nonEnumerableProperty); // "anyone can guess my name" -console.log(Object.keys(obj)); // [] -console.log(Object.getOwnPropertyNames(obj)); // ["nonEnumerableProperty"] - -for (var key in obj) { - console.log(key); // never called -} -``` -Because these keys are non-enumerable, you can't discover them using a `for`-`in` loop. Because `secretKey` is a long string of random characters, you would have a lot of trouble guessing it. And because the `private` module wraps `Object.getOwnPropertyNames` to exclude the keys it generates, you can't even use that interface to discover it. - -Unless you have access to the value of the `secretKey` property name, there is no way to access the value associated with it. So your only responsibility as secret-keeper is to avoid handing out the value of `secretKey` to untrusted code. - -Think of this style as a home-grown version of the first style. Note, however, that it requires a full implementation of ES5's `Object.defineProperty` method in order to make any safety guarantees, whereas the first example will provide safety even in environments that do not support `Object.defineProperty`. - -Rationale ---- - -In JavaScript, the only data that are truly private are local variables -whose values do not *leak* from the scope in which they were defined. - -This notion of *closure privacy* is powerful, and it readily provides some -of the benefits of traditional data privacy, a la Java or C++: -```js -function MyClass(secret) { - this.increment = function() { - return ++secret; - }; -} - -var mc = new MyClass(3); -console.log(mc.increment()); // 4 -``` -You can learn something about `secret` by calling `.increment()`, and you -can increase its value by one as many times as you like, but you can never -decrease its value, because it is completely inaccessible except through -the `.increment` method. And if the `.increment` method were not -available, it would be as if no `secret` variable had ever been declared, -as far as you could tell. - -This style breaks down as soon as you want to inherit methods from the -prototype of a class: -```js -function MyClass(secret) { - this.secret = secret; -} - -MyClass.prototype.increment = function() { - return ++this.secret; -}; -``` -The only way to communicate between the `MyClass` constructor and the -`.increment` method in this example is to manipulate shared properties of -`this`. Unfortunately `this.secret` is now exposed to unlicensed -modification: -```js -var mc = new MyClass(6); -console.log(mc.increment()); // 7 -mc.secret -= Infinity; -console.log(mc.increment()); // -Infinity -mc.secret = "Go home JavaScript, you're drunk."; -mc.increment(); // NaN -``` -Another problem with closure privacy is that it only lends itself to -per-instance privacy, whereas the `private` keyword in most -object-oriented languages indicates that the data member in question is -visible to all instances of the same class. - -Suppose you have a `Node` class with a notion of parents and children: -```js -function Node() { - var parent; - var children = []; - - this.getParent = function() { - return parent; - }; - - this.appendChild = function(child) { - children.push(child); - child.parent = this; // Can this be made to work? - }; -} -``` -The desire here is to allow other `Node` objects to manipulate the value -returned by `.getParent()`, but otherwise disallow any modification of the -`parent` variable. You could expose a `.setParent` function, but then -anyone could call it, and you might as well give up on the getter/setter -pattern. - -This module solves both of these problems. - -Usage ---- - -Let's revisit the `Node` example from above: -```js -var p = require("private").makeAccessor(); - -function Node() { - var privates = p(this); - var children = []; - - this.getParent = function() { - return privates.parent; - }; - - this.appendChild = function(child) { - children.push(child); - var cp = p(child); - if (cp.parent) - cp.parent.removeChild(child); - cp.parent = this; - return child; - }; -} -``` -Now, in order to access the private data of a `Node` object, you need to -have access to the unique `p` function that is being used here. This is -already an improvement over the previous example, because it allows -restricted access by other `Node` instances, but can it help with the -`Node.prototype` problem too? - -Yes it can! -```js -var p = require("private").makeAccessor(); - -function Node() { - p(this).children = []; -} - -var Np = Node.prototype; - -Np.getParent = function() { - return p(this).parent; -}; - -Np.appendChild = function(child) { - p(this).children.push(child); - var cp = p(child); - if (cp.parent) - cp.parent.removeChild(child); - cp.parent = this; - return child; -}; -``` -Because `p` is in scope not only within the `Node` constructor but also -within `Node` methods, we can finally avoid redefining methods every time -the `Node` constructor is called. - -Now, you might be wondering how you can restrict access to `p` so that no -untrusted code is able to call it. The answer is to use your favorite -module pattern, be it CommonJS, AMD `define`, or even the old -Immediately-Invoked Function Expression: -```js -var Node = (function() { - var p = require("private").makeAccessor(); - - function Node() { - p(this).children = []; - } - - var Np = Node.prototype; - - Np.getParent = function() { - return p(this).parent; - }; - - Np.appendChild = function(child) { - p(this).children.push(child); - var cp = p(child); - if (cp.parent) - cp.parent.removeChild(child); - cp.parent = this; - return child; - }; - - return Node; -}()); - -var parent = new Node; -var child = new Node; -parent.appendChild(child); -assert.strictEqual(child.getParent(), parent); -``` -Because this version of `p` never leaks from the enclosing function scope, -only `Node` objects have access to it. - -So, you see, the claim I made at the beginning of this README remains -true: - -> In JavaScript, the only data that are truly private are local variables -> whose values do not *leak* from the scope in which they were defined. - -It just so happens that closure privacy is sufficient to implement a -privacy model similar to that provided by other languages. |