JavaScript: filter() для объектов
ECMAScript 5 имеет filter()
прототип Array
типы, но не Object
типы, если я правильно понял.
как бы я реализовал filter()
на Object
s в JavaScript?
скажем, у меня есть этот объект:
var foo = {
bar: "Yes"
};
и я хочу написать filter()
что работает на 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;
};
это работает, когда я использую его в следующей демонстрации, но когда я добавляю его на свой сайт, который использует jQuery 1.5 и jQuery UI 1.8.9, я получаю Ошибки JavaScript в 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
}
<div id="disp"></div>
8 ответов:
никогда и нигде не распространяется
Object.prototype
.ужасные вещи будут происходить с вашим кодом. Все сломается. Вы расширяетесь все типы объектов, включая литералы объектов.
вот быстрый пример, который вы можете попробовать:
// 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!"
вместо этого создайте функцию, которую вы передаете объекту.
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; };
прежде всего,считается плохой практикой расширять
Object.prototype
. Вместо этого предоставьте свою функцию в качестве функции полезности наObject
, так же, как уже естьObject.keys
,Object.assign
,Object.is
, ...так далее.можно использовать
reduce
иObject.keys
для реализации нужного фильтра (с помощью 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);
обратите внимание, что в приведенном выше коде
predicate
должен быть включение состояние (вопреки исключение условие OP используется), так что он находится в соответствии с тем, какArray.prototype.filter
строительство.С
Object.assign
в приведенном выше решении оператор запятая используется
reduce
часть, чтобы вернуть мутировавший
если вы используете подчеркивание или лодашь, вы можете использовать
pick
(или, напротив,omit
).примеры из документов подчеркивания:
_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age'); // {name: 'moe', age: 50}
или с обратным вызовом (для лодашь используйте pickBy):
_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) { return _.isNumber(value); }); // {age: 50}
как Патрик уже заявил, Это плохая идея, так как она почти наверняка сломает любой сторонний код, который вы когда-либо хотели бы использовать.
все библиотеки, такие как jquery или prototype, сломаются, если вы расширите
Object.prototype
, причина в том, что ленивая итерация над объектами (безhasOwnProperty
проверки) сломается, так как функции, которые вы добавляете, будут частью итерации.
Я создал
Object.filter()
который не только фильтрует по функции, но и принимает массив ключей для включения. Дополнительный третий параметр позволит вам инвертировать фильтр.дано:
var foo = { x: 1, y: 0, z: -1, a: 'Hello', b: 'World' }
время:
Object.filter(foo, ['z', 'a', 'b'], true);
функция:
Object.filter(foo, function (key, value) { return Ext.isString(value); });
код
отказ от ответственности: я решил использовать Ext JS core для краткости. Не посчитал нужным писать шашки типов для типов объектов как это не было частью вопроса.
// Helper functions function clone(obj) { return JSON.parse(JSON.stringify(obj)); } function print(obj) { document.getElementById('disp').innerHTML += JSON.stringify(obj, undefined, ' ') + '<br />'; 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 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/extjs/4.2.1/builds/ext-core.min.js"></script> <div id="disp"></div>
дано
object = {firstname: 'abd', lastname:'tm', age:16, school:'insat'}; keys = ['firstname', 'age'];
затем :
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') )
Как насчет:
function filterObj(keys, obj) { const newObj = {}; for (let key in obj) { if (keys.includes(key)) { newObj[key] = obj[key]; } } return newObj; }
или...
function filterObj(keys, obj) { const newObj = {}; Object.keys(obj).forEach(key => { if (keys.includes(key)) { newObj[key] = obj[key]; } }); return newObj; }
в этих случаях я использую jquery $.карта, которая может обрабатывать объекты. Как уже упоминалось в других ответах, не рекомендуется менять собственные прототипы (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes)
Ниже приведен пример фильтрации, просто проверяя некоторые свойства вашего объекта. Он возвращает собственный объект, если ваше условие истинно или возвращает
undefined
если не. Этотundefined
свойство сделает эту запись исчезнет из списка объектов;$.map(yourObject, (el, index)=>{ return el.yourProperty ? el : undefined; });