如何在 JavaScript 中创建对象的只读/不可变版本,其属性无法更改?这也应该适用于任何子对象的属性等等。
我遇到的所有执行此操作的方法(Object.defineProperty
、Object.freeze
等)仅适用于对象的顶级属性,但不适用于子对象。
(一个可能的用例:在特定模块中创建/修改对象settings
或类型对象后,您需要以不可变的形式将其公开给程序的其余模块。)configuration
如何在 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));