创建任何对象(包括深层属性)的只读/不可变副本
Create a read-only/immutable copy of any object (including deep properties)
如何在JavaScript中创建对象的只读/不可变版本,其属性不能更改?这也应该适用于任何子对象的属性,等等。
我遇到的所有方法(Object.defineProperty
, Object.freeze
等)都只适用于对象的顶层属性,而不适用于子对象。
(一个可能的用例:在特定模块中创建/修改settings
或configuration
类型对象后,您需要以不可变的形式将其公开给程序的其余模块。)
这是我经过深思熟虑后想出的解决方案。很适合我的需要,所以我想分享一下QnA风格。如果你发现了任何改进/问题,请提出建议。
/**
* Make the the specified object (deeply) immutable or "read-only", so that none of its
* properties (or sub-properties) can be modified. The converted object is returned.
* @param {object} obj Input object
*/
makeImmutable: function makeImmutable (obj) {
if ((typeof obj === "object" && obj !== null) ||
(Array.isArray? Array.isArray(obj): obj instanceof Array) ||
(typeof obj === "function")) {
Object.freeze(obj);
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
makeImmutable(obj[key]);
}
}
}
return obj;
}
编辑:简化代码。
对这个解决方案很感兴趣。
下面是一个示例代码片段:/**
* Make the the specified object (deeply) immutable or "read-only", so that none of its
* properties (or sub-properties) can be modified. The converted object is returned.
* @param {object} obj Input object
*/
makeImmutable: function makeImmutable(obj) {
if ((typeof obj === "object" && obj !== null) ||
(Array.isArray ? Array.isArray(obj) : obj instanceof Array) ||
(typeof obj === "function")) {
Object.freeze(obj);
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
makeImmutable(obj[key]);
}
}
}
return obj;
}
var newObj = {
thisArrayOfObjects: [{
propertyOne: 'value1',
propertyTwo: 'value2'
}]
};
newObj.thisArrayOfObjects.push({
propertyBefore: 'before3'
});
console.log('newObj', newObj);
$('#viewer').append('newObj: ' + JSON.stringify(newObj));
makeImmutable(newObj);
console.log('imutable', newObj);
$('#viewer').append('<br/><br/>imutable: ' + JSON.stringify(newObj));
try {
newObj.thisArrayOfObjects.push({
propertyThree: 'value3'
});
} catch (e) {
$('#viewer').append('<br/><br/>immutable error: ' + e.message);
console.log('immutable error:', e.message);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="viewer" />
已经是很棒的答案了。这个是用lodash
:
var _ = require('lodash');
使对象不可变:
/**
* Makes an Object immutable by (deep) freezing all own peoperties.
* @param {*} obj - Object to make immutable.
* @returns {*} The input Object.
*/
function deepFreeze(obj) {
if (_.isObject(obj) || _.isArray(obj) || _.isFunction(obj)) {
Object.freeze(obj);
_.forOwn(obj, deepFreeze);
}
return obj;
}
创建不可变克隆:
var frozenClone = deepFreeze(_.cloneDeep(obj));
相关文章:
- 如何将不可变的js导入angular 2(alpha)
- JavaScript Array unshift() 以一种不可变的方式
- 将对象从另一个不可变的Map分配给Map是否意味着深度克隆
- 函数在不可变的js和redux存储中
- 如何在JS中创建对象的可变和不可变副本
- 使用动态键返回不可变状态
- 不可变的JS映射或列表
- 如何使用不可变表示此数组重新排序示例
- 不可变,在映射内更新不返回正确的对象
- 不可变的Chai断言错误,而预期的结果等于
- 使用扩展运算符和析构函数运算符修改不可变对象的最短方法是什么
- 如何在类似Om的不可变应用程序状态下对关系数据进行建模
- javascript中不可变的值
- 不可变的js修改所有嵌套的记录
- WebSQL:SQLResultSetRowList 中的返回行是不可变的
- 如何在不可变/反应文档页面上阅读代码示例
- 在不可变JS中更新列表中的对象
- Object.seal(Object.prototype)是否使所有对象不可变?
- 冻结一个属性?或者如何将属性设置为不可变/只读
- 创建任何对象(包括深层属性)的只读/不可变副本