深度克隆没有一些字段

时间:2013-01-11 09:48:05

标签: javascript jquery clone deep-copy

让我有下一个javascript对象。现在我想克隆它,但没有一些字段。例如,我想要没有字段"lastName""cars.age"的克隆对象 的输入

{
   "firstName":"Fred",
   "lastName":"McDonald",
      "cars":[
           {
              "type":"mersedes",
              "age":5
           },
           {
              "model":"bmw",
              "age":10
           }
       ]
}  

输出(克隆)

{
   "firstName":"Fred",
   "cars":[
       {
          "model":"mersedes"
       },
       {
          "model":"bmw"
       }
   ]
}   

我可以做类似

的事情
var human = myJson   
var clone = $.extend(true, {}, human)  
delete clone.lastName  
_.each(clone.cars, function(car))  
{  
   delete car.age  
}  

您知道更简单的解决方案吗?

2 个答案:

答案 0 :(得分:6)

如果您不介意添加对象原型,这是一个简单的解决方案。您可能需要修改一些以供自己使用。

Object.prototype.deepOmit = function(blackList) {
  if (!_.isArray(blackList)) { 
    throw new Error("deepOmit(): argument must be an Array");
  }

  var copy = _.omit(this, blackList);
  _.each(blackList, function(arg) {
    if (_.contains(arg, '.')) {
      var key  = _.first(arg.split('.'));
      var last = arg.split('.').slice(1);
      copy[key] = copy[key].deepOmit(last);
    }
  });
  return copy;
};

Array.prototype.deepOmit = function(blackList) {
  if (!_.isArray(blackList)) { 
    throw new Error("deepOmit(): argument must be an Array");
  }

  return _.map(this, function(item) {
    return item.deepOmit(blackList);
  });
};

然后当你有一个像这样的对象时:

var personThatOwnsCars = {
   "firstName":"Fred",
   "lastName":"McDonald",
      "cars":[
           {
              "type":"mersedes",
              "age":5
           },
           {
              "model":"bmw",
              "age":10
           }
       ]
};

你可以做这样的魔法。

personThatOwnsCars.deepOmit(["firstName", "cars.age"]);

甚至像这样的魔法!

[person1, person2].deepOmit(["firstName", "cars.age"]);

答案 1 :(得分:5)

这是一个独立的函数,取决于我写的lodash /下划线也是如此。

它为对象或数组中的每个(value,indexOrKey)对调用一个回调,如果为true,则在结果对象中省略该对。

在访问该值后调用回调,因此您可以省略与您的条件匹配的整个子树。

function deepOmit(sourceObj, callback, thisArg) {
    var destObj, i, shouldOmit, newValue;

    if (_.isUndefined(sourceObj)) {
        return undefined;
    }

    callback = thisArg ? _.bind(callback, thisArg) : callback;

    if (_.isPlainObject(sourceObj)) {
        destObj = {};
        _.forOwn(sourceObj, function(value, key) {
            newValue = deepOmit(value, callback);
            shouldOmit = callback(newValue, key);
            if (!shouldOmit) {
                destObj[key] = newValue;
            }
        });
    } else if (_.isArray(sourceObj)) {
        destObj = [];
        for (i = 0; i <sourceObj.length; i++) {
            newValue = deepOmit(sourceObj[i], callback);
            shouldOmit = callback(newValue, i);
            if (!shouldOmit) {
                destObj.push(newValue);
            }
        }
    } else {
        return sourceObj;
    }

    return destObj;
}

一些样本

var sourceObj = {
    a1: [ undefined, {}, { o: undefined } ],
    a2: [ 1, undefined ],
    o: { s: 's' } 
};

deepOmit(sourceObj, function (value) {
    return value === undefined;
});
//=> { a1: [ {}, {} ], a2: [ 1 ], o: { s: 's' }}

//omit empty objects and arrays too
deepOmit(sourceObj, function (value) {
    return value === undefined ||
        (_.isPlainObject(value) && !_.keys(value).length) ||
        (_.isArray(value) && !value.length);
});
//=> { a2: [ 1 ], o: { s: 's' }}

//indexOrKey is the string key or the numeric index if the object is array
deepOmit([ 0, 1, 2, 3, 4 ], function (value, indexOrKey) {
    return indexOrKey % 2;
});
//=> [ 0, 2, 4 ]