Skip to content

Instantly share code, notes, and snippets.

@voodoohop
Created December 14, 2014 16:37
Show Gist options
  • Save voodoohop/19cdebddb6d67c94c0bd to your computer and use it in GitHub Desktop.
Save voodoohop/19cdebddb6d67c94c0bd to your computer and use it in GitHub Desktop.
Lazy Immutable Object using ES6 Proxies to create a "Virtual Object"
var _ = require("lodash");
require('harmony-reflect');
const nothing = {};
const deleteMe= {DELETED:true};
var immutableTom = function(initial) {
var wrapNewProps = (target, newProps) => {
// console.log("wrapping",target," with newProps",newProps);
var setFunc = (name, val=deleteMe) => wrapNewProps(newProxy, typeof name === "string" ? {[name]:val}:name)
var getFunc = (name) => {
var res = newProps && newProps.hasOwnProperty(name) && newProps[name] ? newProps[name] : target[name];
return res === deleteMe ? undefined:res;
};
var keysFunc = () => _.filter(_.union(Object.keys(target),Object.keys(newProps)),(k) => !(newProps[k] == deleteMe));
var hasCheck = (name) =>
(newProps.hasOwnProperty(name) && newProps[name] != deleteMe) || (!newProps.hasOwnProperty(name) && target.hasOwnProperty(name) && target[name] != deleteMe);
var getPropDescriptor = name => name==="set"? {value: setFunc, enumerable:false,configurable:true} : (getFunc(name) === undefined ? undefined : {value: getFunc(name), enumerable:true, configurable:true})
var newProxy = new Proxy(nothing, {
get: (t, name, receiver) => {
if (name === "set")
return setFunc;
if (name === "delete")
return setFunc;
return getFunc(name);
},
set: (...args) => {throw ["tried mutating immutableTom",args,target]},
has: (t, name) => hasCheck(name),
hasOwn: (t, name) => hasCheck(name),
iterate: (t) => keysFunc().map(k => getFunc(k)),
enumerate: keysFunc,
preventExtension: () => false,
isExtensible: () => true,
ownKeys: keysFunc,
getPropertyNames: keysFunc,
getOwnPropertyNames: keysFunc,
getOwnPropertyDescriptor: (t,name) => getPropDescriptor(name),
deleteProperty: (...args) => {throw ["tried deleting from immutableTom",args,target]}
});
return newProxy;
}
return wrapNewProps(nothing,initial);
}
var assert = require("assert");
var test1 = immutableTom({bla:2}).set("test",5);
assert.equal(test1.bla,2);
assert.equal(test1.test,5);
assert.throws(() => test1.x = 2);
assert.throws(() => delete test1.bla );
var deletedProp = test1.delete("bla");
assert.equal(deletedProp.bla,undefined);
assert.equal(deletedProp.hasOwnProperty("bla"),false);
console.log("immutableTom Test1", test1, test1.test, Object.keys(test1));
export default immutableTom;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment