Created
February 27, 2012 09:37
-
-
Save shesek/1922813 to your computer and use it in GitHub Desktop.
JavaScript per-instance private storage area
This file contains hidden or 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
# A simple implementation to get a private storage area for objects. | |
# Also allows setting default properties for the storage area. | |
# Written in CoffeeScript: (with an added `export` function. On the regular version, use `exports.privates = ...`) | |
export privates = do -> | |
counter=0 | |
(proto) -> | |
key = "__id#{ ++counter }" | |
store = [] | |
(object) -> store[object[key] ||= store.length] ||= Object.create proto or null | |
# (Object.create shim required for it to work on ES3) | |
### | |
# JavaScript Version | |
(function(exports) { | |
var counter = 0; | |
exports.privates = function(proto) { | |
var key = '__id' + ++counter, | |
store = []; | |
return function(object) { | |
var idx = (object[key] || (object[key] = store.length)); | |
return store[idx] || (store[idx] = Object.create(proto||null)); | |
} | |
} | |
})(exports||window); | |
### | |
class Hello | |
private = privates | |
say: (text) -> console.log "Say: #{ text }" | |
world: 'World' | |
talk: -> private(this).say "Hello, #{private(this).world}" | |
setWorld: (value) -> private(this).world = value | |
code = new Hello | |
code.setWorld 'Code' | |
code.talk() # Say: Hello, Code | |
world = new Hello | |
world.talk() # Say: Hello, World | |
# Obviosuly, doesn't work with a different copy of the private() function | |
private = privates() | |
private(world).world = 'Foobar' | |
world.talk() # Still 'World'. | |
# However, while its impossible to read/write data to private areas, it is possible to replace the property used to | |
# track internal index. | |
world['__id1'] = code['__id1'] | |
world.talk() # Say: Hello, //code//. | |
# This is fixable by either using the ECMAScript.next WeakMap (only on Mozilla 6 and highly experimental) instead of | |
# storing the internal index as a property, or by using ECMAScript5 Object.defineProperty() to set the property's | |
# attributes writable, configurable and enumerable to false (only FF4+, Chrome5+, IE9+ and Safari5+). It'll take some | |
# time until WeakMap are used widely enough to be considered for client-side production, and defining the property | |
# attributes won't work on, as usual, the majority of IE users - making it not 100% secure on the client side, but it | |
# works well on server-side environments like NodeJS and Rhino. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment