Deep clone without some fields

2020-06-12 04:01发布

Let's I have next javascript object. Now I want clone it but without some fields. For example I want cloned object without field "lastName" and "cars.age"
Input

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

Output (cloned)

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

I can do something like

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

Do you know easier solution?

2条回答
淡お忘
2楼-- · 2020-06-12 04:32

If you don't mind adding to object prototypes, this is an easy solution. You may want to modify it some for your own use.

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

Then when you have an object like:

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

You can do magic like this.

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

Or even magic like this!

[person1, person2].deepOmit(["firstName", "cars.age"]);
查看更多
闹够了就滚
3楼-- · 2020-06-12 04:37

Here is a standalone function depending on lodash/underscore that i've written that does the same.

It calls a callback for each (value, indexOrKey) pair in the object or array and if true will omit that pair in the resulting object.

The callback is called after the value has been visited so you can omit a whole sub-tree of values that match your condition.

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

Some samples

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 ]
查看更多
登录 后发表回答