Last active
January 1, 2016 00:49
-
-
Save bolshchikov/8069009 to your computer and use it in GitHub Desktop.
Creating read-only JS object
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
// lo-dash lib is the dependency | |
function readOnly(target){ | |
var _readOnly = function (target, acc) { | |
// acc is passed into the function to be used for observer | |
var _defineProperty = function (propName, target, acc) { | |
var i, len; | |
// operation to be performed when add occurred | |
var addOp = function (cArg) { | |
// have to define the added item | |
_defineProperty(cArg.name, cArg.object, acc[propName]); | |
}; | |
// operation to be performed when add delete | |
var delOp = function (cArg) { | |
if (_.isPlainObject(cArg.object)) { | |
delete acc[propName][cArg.name]; | |
} | |
if (_.isArray(cArg.object)) { | |
// this fixes the array | |
acc[propName].unshift(acc[propName].shift()); | |
// when splice occures, there's no | |
// clear indication what has been removed | |
// so, we need to find the diff, and clear acc | |
var args = _.difference(acc[propName], cArg.object); | |
args.unshift(acc[propName]); | |
_.pull.apply(null, args); | |
} | |
}; | |
// function that is called when any change in the property happens | |
var observeFn = function (changes) { | |
for (i = 0, len = changes.length; i < len; i += 1) { | |
switch(changes[i].type) { | |
case 'new': | |
addOp(changes[i]); | |
break; | |
case 'deleted': | |
delOp(changes[i]); | |
break; | |
default: | |
continue; | |
} | |
} | |
}; | |
if (_.isArray(target[propName])) { | |
Object.defineProperty(acc, propName, { | |
configurable: true, | |
enumerable: true, | |
value: [] | |
}); | |
Object.observe(target[propName], observeFn); | |
_readOnly(target[propName], acc[propName]); | |
} | |
else if (_.isPlainObject(target[propName])) { | |
Object.defineProperty(acc, propName, { | |
configurable: true, | |
enumerable: true, | |
value: {} | |
}); | |
Object.observe(target[propName], observeFn); | |
_readOnly(target[propName], acc[propName]); | |
} | |
// value is the primitive one | |
else { | |
Object.defineProperty(acc, propName, { | |
configurable: true, | |
enumerable: true, | |
get: function () { | |
return target[propName]; | |
} | |
}); | |
} | |
}; | |
// target is an array | |
_.forEach(target, function (val, key) { | |
_defineProperty(key, target, acc); | |
}); | |
return acc; | |
}; | |
if (Array.isArray(target)) { | |
return _readOnly(target, []); | |
} | |
else { | |
return _readOnly(target, {}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment