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

Javascript: object's setter and getter is lost after clonning / copying / extending

我希望能够复制一个保持 getter and 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

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

"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 提供的 link 所指出的,原因似乎是 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 有关。

它的发生是因为 deep/shallow:

"A lazy copy is a combination of both shallow copy and deep copy. When initially copying an object, a (fast) shallow copy is used. A counter is also used to track how many objects share the data."

请阅读this or check this answer to make it more clear or even angular docs

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

如您所见,"enumeration" 不是必需的。到目前为止,这段代码似乎已经解决了我的问题。感谢 Steven Vachon。

这个问题有很多答案,我测试了大部分但不是全部。