JavaScript: filter () para objects

O ECMAScript 5 possui o protótipo filter() para os tipos Array , mas não para os tipos Object , se bem entendi.

Como eu implementaria um filter() para o Object s em JavaScript?

Digamos que eu tenha esse object:

 var foo = { bar: "Yes" }; 

E eu quero escrever um filter() que funciona no 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; }; 

Isso funciona quando eu usá-lo na demonstração a seguir, mas quando eu adicioná-lo ao meu site que usa o jQuery 1.5 e jQuery UI 1.8.9, recebo erros de JavaScript no 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 } 
 

Nunca estenda o Object.prototype .

Coisas horríveis acontecerão com o seu código. As coisas vão quebrar. Você está estendendo todos os tipos de object, incluindo literais de object.

Aqui está um exemplo rápido que você pode tentar:

  // 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!" 

Em vez disso, crie uma function que você passe o 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; }; 

Primeiro de tudo, é considerado uma prática ruim estender o Object.prototype . Em vez disso, forneça seu recurso como function de utilitário no Object , assim como já existem Object.keys , Object.assign , Object.is , … etc.

Você pode usar reduce Object.keys reduce e Object.keys para implementar o filtro desejado (usando a syntax de seta do ES6):

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

Se você estiver disposto a usar sublinhado ou lodash , você pode usar pick (ou o oposto, omit ).

Exemplos dos documentos do sublinhado:

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

Ou com um retorno de chamada (para o lodash , use pickBy ):

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

Como patrick já afirmou, esta é uma má idéia, já que quase certamente quebrará qualquer código de terceiros que você possa desejar usar.

Todas as bibliotecas como jquery ou prototype serão quebradas se você estender Object.prototype , o motivo é que a iteração preguiçosa sobre objects (sem verificações de hasOwnProperty ) será interrompida, já que as funções adicionadas farão parte da iteração.

Eu criei um Object.filter() que não só filtrar por uma function, mas também aceita uma matriz de chaves para include. O terceiro parâmetro opcional permitirá que você inverta o filtro.

Dado:

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

Array:

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

Função:

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

Código

Disclaimer : Eu escolhi usar o núcleo Ext JS para ser breve. Não achava necessário escrever verificadores de tipo para tipos de objects, pois não fazia parte da pergunta.

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

E se:

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

Ou…

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

Dado

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

então :

 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') )