2013-01-11 11 views
10

Lassen Sie mich nächste Javascript-Objekt haben. Jetzt will ich es klonen aber ohne einige Felder. Zum Beispiel möchte ich Objekt ohne Feld, das Sie so etwas wieDeep Clone ohne einige Felder

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

Do "lastName" und "cars.age" geklont
Eingang

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

Output (geklont)

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

ich tun kann, wissen einfachere Lösung?

+1

Es gibt keinen Weg '.extend' $ mit geklonten Mitgliedern, um herauszufiltern, aber Sie können Ihre eigene Implementierung rollen, die Felder auslässt ... –

+0

würde ich erstellen Funktion, die ein zu klonendes Objekt und ein Array von Eigenschaften akzeptiert, die in Ihrem neuen Objekt entfernt (oder eingeschlossen) werden sollen. Es gibt keine integrierte Methode, um dies in jQuery zu tun. –

+0

Underscore.js enthält die Funktion "pluck", die eine Art umgekehrte Version dessen ist, was Sie wollen: Geben Sie an, was Sie einschließen möchten und nicht, was Sie weglassen möchten. Vielleicht könnte das ein Ausgangspunkt für Ihre Implementierung sein? – Henrik

Antwort

6

Wenn es Ihnen nichts ausmacht, Objektprototypen hinzuzufügen, ist dies eine einfache Lösung. Vielleicht möchten Sie es für Ihre eigenen Zwecke ändern.

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

Dann, wenn Sie ein Objekt wie haben:

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

Sie können wie diese Magie tun.

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

Oder sogar Magie so!

+2

Wenn du bereits Unterstriche verwendest, ist es wahrscheinlich besser' _.mixin' anstelle von Prototypen zu verwenden. –

5

Hier ist eine eigenständige Funktion abhängig von lodash/Unterstrich, die ich geschrieben habe, die das gleiche tut.

Sie ruft einen Callback für jedes Paar (value, indexOrKey) im Objekt oder Array auf und wenn true, wird dieses Paar im resultierenden Objekt ausgelassen.

Der Rückruf wird aufgerufen, nachdem der Wert aufgerufen wurde, sodass Sie eine ganze Unterstruktur mit Werten auslassen können, die Ihrer Bedingung entsprechen.

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

Einige Proben

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 ]