簡體   English   中英

創建任何對象的只讀/不可變副本(包括深層屬性)

[英]Create a read-only/immutable copy of any object (including deep properties)

如何在JavaScript中創建對象的只讀/不可變版本,其屬性無法更改? 這也應該適用於任何子對象的屬性等。

我遇到的所有方法( Object.definePropertyObject.freeze等)僅適用於對象的頂級屬性,但不適用於子對象。

(可能的用例:在特定模塊中創建/修改settingsconfiguration類型對象后,需要以不可變的形式將其公開給程序的其余模塊。)

經過一番思考后,我想出了這個解決方案。 適合我的需求,所以我想我會分享它的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));

為什么yelded object '#<object> ' 只讀?<div id="text_translate"><p> 我使用 yield 實現了一個簡單的搜索 - 通過遞歸文件夾結構運行,產生所有文件夾。 我的實現相當簡單,我刪除了所有“const”(以防萬一)</p><pre> function *folders(f: Folder): IterableIterator&lt;Folder&gt; { yield f; if (f.folders) { for (let sf of f.folders) { yield* folders(sf); } } } function *allFolders(): IterableIterator&lt;Folder&gt; { for (let p of projects) { yield* folders(p.project.rootFolder!) } }</pre><p> 當我嘗試修改返回的 object</p><pre> let folders = allFolders(); let t = folders.next().value; t.name = "sdvs";</pre><p> 我明白了</p><pre>TypeError: Cannot assign to read only property 'name' of object '#&lt;Object&gt;'</pre><p> 如果我直接訪問 object (它位於此文件中的全局 scope 中)就可以了。 我現在已經花了幾個小時在這上面,我完全感到困惑。 這根本不可能嗎? 為什么會發生這種情況?</p></div></object>

[英]Why is yelded object '#<Object>' read-only?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

相關問題 對象只讀屬性 可以在JavaScript中創建對對象外部代碼只讀的屬性嗎? Object.freeze凍結屬性? 或如何將屬性設置為不可變/只讀? Javascript對象中的只讀屬性真的是只讀的嗎? Object.create()只讀名稱屬性 如何將具有只讀成員的javascript對象復制到非只讀成員? 瀏覽器 JavaScript 中的只讀屬性 在 JavaScript 中定義只讀屬性 React prop的本地副本是只讀的 為什么yelded object '#<object> ' 只讀?<div id="text_translate"><p> 我使用 yield 實現了一個簡單的搜索 - 通過遞歸文件夾結構運行,產生所有文件夾。 我的實現相當簡單,我刪除了所有“const”(以防萬一)</p><pre> function *folders(f: Folder): IterableIterator&lt;Folder&gt; { yield f; if (f.folders) { for (let sf of f.folders) { yield* folders(sf); } } } function *allFolders(): IterableIterator&lt;Folder&gt; { for (let p of projects) { yield* folders(p.project.rootFolder!) } }</pre><p> 當我嘗試修改返回的 object</p><pre> let folders = allFolders(); let t = folders.next().value; t.name = "sdvs";</pre><p> 我明白了</p><pre>TypeError: Cannot assign to read only property 'name' of object '#&lt;Object&gt;'</pre><p> 如果我直接訪問 object (它位於此文件中的全局 scope 中)就可以了。 我現在已經花了幾個小時在這上面,我完全感到困惑。 這根本不可能嗎? 為什么會發生這種情況?</p></div></object>
 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM