【问题标题】:Create a read-only/immutable copy of any object (including deep properties)创建任何对象的只读/不可变副本(包括深层属性)
【发布时间】:2013-04-10 10:58:21
【问题描述】:

如何在 JavaScript 中创建一个只读/不可变版本的对象,其属性不能更改?这也应该适用于任何子对象的属性等等。

我遇到的所有执行此操作的方法(Object.definePropertyObject.freeze 等)仅适用于对象的顶级属性,但不适用于子对象。

(一个可能的用例:在特定模块中创建/修改settingsconfiguration 类型对象后,您需要以不可变的形式将其公开给程序的其余模块。)

【问题讨论】:

    标签: javascript object constants immutability readonly


    【解决方案1】:

    这是我经过一番思考后想出的解决方案。非常适合我的需求,所以我想我会分享它 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;
    }
    

    编辑: 简化了代码。现在也能正确处理数组了。

    【讨论】:

    • 很好的解决方案。我使用该解决方案在下面创建了一个代码 sn-p 来展示它的使用方式和证明。 Upvoted
    【解决方案2】:

    对这个解决方案很感兴趣。

    这里是带有示例的代码 sn-p:

    /**
     * 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" />

    【讨论】:

      【解决方案3】:

      已经有了很好的答案。这个用的是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));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-26
        • 1970-01-01
        相关资源
        最近更新 更多