Javascript:对象设置器和获取器在克隆/复制/扩展后丢失

Posted

技术标签:

【中文标题】Javascript:对象设置器和获取器在克隆/复制/扩展后丢失【英文标题】:Javascript: object's setter and getter is lost after clonning / copying / extending 【发布时间】:2016-01-17 08:44:11 【问题描述】:

我希望能够复制一个保持getter 和setter 功能的对象。

注意:这个问题是关于 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;
  ...
);

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

** 更新:

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

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

我手动添加了“可枚举”属性:

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 有关。

【问题讨论】:

github.com/angular/angular.js/issues/5085 @RichS:感谢您找到该链接!这就解释了一切……我们只需要一些解决方案吗?顺便说一句,我使用的是角度 1.4.4。我会尝试测试版。 【参考方案1】:

它的发生是因为深/浅:

“惰性复制是浅拷贝和深拷贝的组合。最初复制对象时,使用(快速)浅拷贝。还使用计数器来跟踪有多少对象共享数据。”

请阅读this 或检查此answer 以使其更清晰甚至有角度docs

【讨论】:

【参考方案2】:

我在这个问题中找到了解决方案: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。

这个问题有很多解决方案,我测试了其中的大部分,但不是全部。

【讨论】:

以上是关于Javascript:对象设置器和获取器在克隆/复制/扩展后丢失的主要内容,如果未能解决你的问题,请参考以下文章

Python 装饰器在类中获取或设置字典值

Android:时间选择器和日期选择器在同一个对话框中

JavaScript设计模式与开发实践 迭代器模式

Java对象的浅克隆

迭代器生成器装饰器和标准库

python 对象克隆