[removed] object's setter and getter is lost a

2019-08-07 14:35发布

问题:

I would like to be able to copy an object keeping getter and setter functionality.

NOTE: This question is about angularjs but it may apply to many other frameworks as well.

Code available at: 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);

Output:

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

Why "set val" is not triggered anymore after "angular.copy" ? As you can see, the value is correctly stored.

"angular.extend" keeps the references, so updating sExt will update sObj, which I don't want.

I'm copying an scope object before passing it into a controller (modal):

    $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;
  ...
});

Any ideas on how to copy sObj without loosing "set" and "get" and without keeping references?

** UPDATE:

As pointed by the link provided by RichS, it seems that the reason is that getter and setter properties are not enumerable and thus they are not copied over. This question is closely related (or duplicated if we go to the source of the problem): Copy object with results of getters

I updated the code: https://jsfiddle.net/vwb04d4f/3/

I added manually the "enumerable" property:

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;
};

However neither extend (from empty object) or copy do actually the job. Perhaps am I missing something?

** UPDATE 2 **

As this problem is not just related to angularjs.

回答1:

I found a solution in this question: 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;
}

See the updated code here:https://jsfiddle.net/vwb04d4f/6/

As you can see, "enumeration" is not required. So far this code seems to have solved my problem. Thanks goes to Steven Vachon.

There are plenty of solutions in that question, I tested most of them but not all.



回答2:

it's happening because of 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."

Please read this or check this answer to make it more clear or even angular docs