Javascript:在克隆/复制/扩展后,对象的setter和getter会丢失

时间:2015-10-19 05:11:16

标签: javascript clone setter getter

我希望能够复制一个保留gettersetter功能的对象。

注意:这个问题是关于angularjs的,但它也可能适用于许多其他框架。

代码见:https://jsfiddle.net/vwb04d4f/2/

function out(str) {
    document.getElementById('body').innerHTML += str + "<br>";
}

var SomeObj = function () {
  var obj = {
    _val: 0,
    set val(value) {
       out("Set: " + value);
        this._val = value;
    },
    get val() {
        return this._val;
    }
  }
  return obj;
};

var sObj = new SomeObj();
sObj.val = 100;

var sCopy = angular.copy(sObj);
sCopy.val = 200;
out("Value:" + sCopy.val);

var sExt = angular.extend(sObj);
sExt.val = 300;

out("Value: " + sObj.val);

输出:

Set: 100
Value:200
Set: 300
Value: 300

为什么“angular.copy”之后不再触发“set val”?如您所见,该值已正确存储。

“angular.extend”保留引用,因此更新sExt将更新sObj,这是我不想要的。

我在将范围对象传递给控制器​​(模态)之前复制它:

    $modal.open({
      animation: true,
      templateUrl: '/html/settings.html',
      controller: 'ModalInstanceCtrl',
      backdrop: false,
      resolve: {
          config: function() {
                var cfgcpy = {};
                angular.copy($scope.config, cfgcpy);
                return cfgcpy;
          }
      }
    }).result.then(function(res){
        ok_func(res);
        close_func();
    }, function() {
        close_func();
    });

angular.module('app').controller('ModalInstanceCtrl', function ($scope, $modalInstance, config) {
  $scope.config = config;
  ...
});

关于如何复制sObj而不丢失“set”和“get”并且不保留引用的任何想法?

**更新:

正如RichS提供的链接所指出的那样,似乎原因是getter和setter属性不可枚举,因此它们不会被复制。这个问题密切相关(如果我们找到问题的根源,则重复):Copy object with results of getters

我更新了代码:https://jsfiddle.net/vwb04d4f/3/

我手动添加了“enumerable”属性:

var SomeObj = function () {
  var obj = {
    _val: 0 
  }
  Object.defineProperty(obj, "val", {
        enumerable: true,
        set : function(value) {
           out("Set: " + value);
           this._val = value;
        },
        get: function(){
            return this._val;
        }
  });
  return obj;
};

然而,无论是扩展(从空对象)还是复制都不能实际完成工作。也许我错过了什么?

**更新2 **

因为这个问题不仅与angularjs有关。

2 个答案:

答案 0 :(得分:3)

我在这个问题中找到了一个解决方案:What is the most efficient way to deep clone an object in JavaScript?

function cloneObject(source) {
    var key,value;
    var clone = Object.create(source);

    for (key in source) {
        if (source.hasOwnProperty(key) === true) {
            value = source[key];

            if (value!==null && typeof value==="object") {
                clone[key] = cloneObject(value);
            } else {
                clone[key] = value;
            }
        }
    }
    return clone;
}

请在此处查看更新后的代码:https://jsfiddle.net/vwb04d4f/6/

如您所见,“枚举”不是必需的。到目前为止,这段代码似乎解决了我的问题。谢谢Steven Vachon。

在这个问题上有很多解决方案,我测试了大部分解决方案,但并非全部。

答案 1 :(得分:0)

由于深度/浅度,它正在发生:

“惰性副本是浅拷贝和深拷贝的组合。当最初复制对象时,使用(快速)浅拷贝。计数器也用于跟踪共享数据的对象数。”

请阅读this或查看answer以使其更清晰甚至更有棱角docs