JavaScript: filter () per Objects

ECMAScript 5 ha il prototipo filter() per i tipi di Array , ma non i tipi di Object , se ho capito bene.

Come implementare un filter() per Object s in JavaScript?

Diciamo che ho questo object:

 var foo = { bar: "Yes" }; 

E voglio scrivere un filter() che funzioni su Object s:

 Object.prototype.filter = function(predicate) { var result = {}; for (key in this) { if (this.hasOwnProperty(key) && !predicate(this[key])) { result[key] = this[key]; } } return result; }; 

Funziona quando lo uso nella demo seguente, ma quando lo aggiungo al mio sito che utilizza jQuery 1.5 e jQuery UI 1.8.9, ottengo errori JavaScript in FireBug.

 Object.prototype.filter = function(predicate) { var result = {}; for (key in this) { if (this.hasOwnProperty(key) && !predicate(this[key])) { console.log("copying"); result[key] = this[key]; } } return result; }; var foo = { bar: "Yes", moo: undefined }; foo = foo.filter(function(property) { return typeof property === "undefined"; }); document.getElementById('disp').innerHTML = JSON.stringify(foo, undefined, ' '); console.log(foo); 
 #disp { white-space: pre; font-family: monospace } 
 

Mai e poi mai estendere Object.prototype .

Cose orribili succederanno al tuo codice. Le cose si romperanno. Stai estendendo tutti i tipi di object, inclusi i letterali degli oggetti.

Ecco un esempio veloce che puoi provare:

  // Extend Object.prototype Object.prototype.extended = "I'm everywhere!"; // See the result alert( {}.extended ); // "I'm everywhere!" alert( [].extended ); // "I'm everywhere!" alert( new Date().extended ); // "I'm everywhere!" alert( 3..extended ); // "I'm everywhere!" alert( true.extended ); // "I'm everywhere!" alert( "here?".extended ); // "I'm everywhere!" 

Invece crea una funzione per passare l’object.

 Object.filter = function( obj, predicate) { var result = {}, key; // ---------------^---- as noted by @CMS, // always declare variables with the "var" keyword for (key in obj) { if (obj.hasOwnProperty(key) && !predicate(obj[key])) { result[key] = obj[key]; } } return result; }; 

Prima di tutto, è considerata una ctriggers pratica estendere Object.prototype . Invece, fornire la funzione come funzione di utilità su Object , proprio come già ci sono Object.keys , Object.assign , Object.is , … ecc.

È ansible utilizzare reduce e Object.keys per implementare il filtro desiderato (utilizzando la syntax della freccia ES6):

 Object.filter = (obj, predicate) => Object.keys(obj) .filter( key => predicate(obj[key]) ) .reduce( (res, key) => (res[key] = obj[key], res), {} ); // Example use: var scores = { John: 2, Sarah: 3, Janet: 1 }; var filtered = Object.filter(scores, score => score > 1); console.log(filtered); 

Se sei disposto a usare underscore o lodash , puoi usare pick (o il suo contrario, omit ).

Esempi dai documenti del underscore:

 _.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age'); // {name: 'moe', age: 50} 

O con un callback (per lodash , usa pickBy ):

 _.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) { return _.isNumber(value); }); // {age: 50} 

Come già affermato da Patrick, questa è una pessima idea, poiché quasi sicuramente infrangerà qualsiasi codice di terze parti che potresti desiderare di utilizzare.

Tutte le librerie come jquery o prototype si interromperanno se estendete Object.prototype , il motivo è che l’iterazione pigra sugli oggetti (senza i controlli hasOwnProperty ) si interromperà poiché le funzioni aggiunte saranno parte dell’iterazione.

Ho creato un Object.filter() che non solo filtra per una funzione, ma accetta anche un array di chiavi da includere. Il terzo parametro opzionale ti permetterà di invertire il filtro.

Dato:

 var foo = { x: 1, y: 0, z: -1, a: 'Hello', b: 'World' } 

Array:

 Object.filter(foo, ['z', 'a', 'b'], true); 

Funzione:

 Object.filter(foo, function (key, value) { return Ext.isString(value); }); 

Codice

Disclaimer : ho scelto di usare il core Ext JS per brevità. Non ritenevo necessario scrivere tipi di controllo per i tipi di object in quanto non faceva parte della domanda.

 // Helper functions function clone(obj) { return JSON.parse(JSON.stringify(obj)); } function print(obj) { document.getElementById('disp').innerHTML += JSON.stringify(obj, undefined, ' ') + '
'; console.log(obj); } Object.filter = function (obj, ignore, invert) { if (ignore === undefined) { return obj; } invert = invert || false; var not = function(condition, yes) { return yes ? !condition : condition; }; var isArray = Ext.isArray(ignore); for (var key in obj) { if (obj.hasOwnProperty(key) && (isArray && not(!Ext.Array.contains(ignore, key), invert)) || (!isArray && not(!ignore.call(undefined, key, obj[key]), invert))) { delete obj[key]; } } return obj; }; var foo = { x: 1, y: 0, z: -1, a: 'Hello', b: 'World' }, bar = clone(foo); print(Object.filter(foo, ['z', 'a', 'b'], true)); print(Object.filter(bar, function (key, value) { return Ext.isString(value); }));
 #disp { white-space: pre; font-family: monospace } 
  

Che ne dite di:

 function filterObj(keys, obj) { const newObj = {}; for (let key in obj) { if (keys.includes(key)) { newObj[key] = obj[key]; } } return newObj; } 

O…

 function filterObj(keys, obj) { const newObj = {}; Object.keys(obj).forEach(key => { if (keys.includes(key)) { newObj[key] = obj[key]; } }); return newObj; } 

Dato

 object = {firstname: 'abd', lastname:'tm', age:16, school:'insat'}; keys = ['firstname', 'age']; 

poi :

 keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {}); // {firstname:'abd', age: 16} 
 // Helper function filter(object, ...keys) { return keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {}); }; //Example const person = {firstname: 'abd', lastname:'tm', age:16, school:'insat'}; // Expected to pick only firstname and age keys console.log( filter(person, 'firstname', 'age') ) 

In questi casi uso jquery $ .map, che può gestire oggetti. Come menzionato in altre risposte, non è una buona pratica modificare i prototipi nativi ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes )

Di seguito è riportato un esempio di filtro semplicemente controllando alcune proprietà del tuo object. Restituisce il proprio object se la tua condizione è vera o restituisce undefined se non lo è. La proprietà undefined farà scomparire quel record dalla lista degli oggetti;

 $.map(yourObject, (el, index)=>{ return el.yourProperty ? el : undefined; });