ECMAScript 5 heeft het filter()
-prototype voor Array
-typen, maar niet voor Object
-typen, als ik het goed begrijp.
Hoe zou ik een filter()
voor Object
s in JavaScript implementeren?
Stel dat ik dit object heb:
var foo = {
bar: "Yes"
};
En ik wil een filter()
schrijven die werkt op 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;
};
Dit werkt als ik het in de volgende demo gebruik, maar als ik het toevoeg aan mijn site die jQuery 1.5 en jQuery UI 1.8.9 gebruikt, krijg ik JavaScript-fouten in FireBug.
Antwoord 1, autoriteit 100%
Verleng nooit Object.prototype
.
Er zullen vreselijke dingen gebeuren met je code. Er gaan dingen kapot. U breidt alleobjecttypen uit, inclusief letterlijke objecten.
Hier is een snel voorbeeld dat u kunt proberen:
// 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!"
Maak in plaats daarvan een functie die u het object doorgeeft.
Object.filter = function( obj, predicate) {
let result = {}, key;
for (key in obj) {
if (obj.hasOwnProperty(key) && !predicate(obj[key])) {
result[key] = obj[key];
}
}
return result;
};
Antwoord 2, autoriteit 97%
Allereerst het wordt als een slechte gewoonte beschouwd om Object.prototype
. Geef in plaats daarvan uw functie als hulpprogramma-functie op Object
, net zoals er al zijn Object.keys
, Object.assign
, Object.is
, …enz.
Ik bied hier verschillende oplossingen:
- Gebruik
reduce
enObject.keys
- Als (1), in combinatie met
Object.assign
- Gebruik
map
en spreid syntaxis in plaats vanreduce
- Gebruik
Object.entries
enObject.fromEntries
1. Gebruik reduce
en Object.keys
Met reduce
en Object.keys
om het gewenste filter te implementeren (met ES6 pijlsyntaxis):
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);
Antwoord 3, autoriteit 33%
Oplossing in Vanilla JS vanaf jaar 2020.
let romNumbers={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
U kunt romNumbers
-object filteren op sleutel:
const filteredByKey = Object.fromEntries(
Object.entries(romNumbers).filter(([key, value]) => key === 'I') )
// filteredByKey = {I: 1}
Of filter romNumbers
object op waarde:
const filteredByValue = Object.fromEntries(
Object.entries(romNumbers).filter(([key, value]) => value === 5) )
// filteredByValue = {V: 5}
Antwoord 4, autoriteit 11%
Als u bereid bent underscoreof lodashte gebruiken, kunt u pick
(of het tegenovergestelde, omit
).
Voorbeelden uit documenten met onderstrepingstekens:
_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
// {name: 'moe', age: 50}
Of met een callback (voor lodash, gebruik pickBy):
_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
return _.isNumber(value);
});
// {age: 50}
Antwoord 5, autoriteit 6%
ES6benadering…
Stel je voor dat je dit object hieronder hebt:
const developers = {
1: {
id: 1,
name: "Brendan",
family: "Eich"
},
2: {
id: 2,
name: "John",
family: "Resig"
},
3: {
id: 3,
name: "Alireza",
family: "Dezfoolian"
}
};
Een functie maken:
const filterObject = (obj, filter, filterValue) =>
Object.keys(obj).reduce((acc, val) =>
(obj[val][filter] === filterValue ? acc : {
...acc,
[val]: obj[val]
}
), {});
En noem het:
filterObject(developers, "name", "Alireza");
en zal terugkeren:
{
1: {
id: 1,
name: "Brendan",
family: "Eich"
},
2: {
id: 2,
name: "John",
family: "Resig"
}
}
Antwoord 6, autoriteit 3%
Zoals Patrick al zei, is dit een slecht idee, omdat het vrijwel zeker elke code van derden zal breken die je ooit zou willen gebruiken.
Alle bibliotheken zoals jQuery of prototype zullen breken als u Object.prototype
uitbreidt, de reden hiervoor is dat luie iteratie over objecten (zonder hasOwnProperty
-controles) zal breken omdat de functies die u toevoegt, maakt deel uit van de iteratie.
Antwoord 7, autoriteit 2%
Wat dacht je van:
function filterObj(keys, obj) {
const newObj = {};
for (let key in obj) {
if (keys.includes(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
Of…
function filterObj(keys, obj) {
const newObj = {};
Object.keys(obj).forEach(key => {
if (keys.includes(key)) {
newObj[key] = obj[key];
}
});
return newObj;
}
Antwoord 8, autoriteit 2%
Gegeven
object = {firstname: 'abd', lastname:'tm', age:16, school:'insat'};
keys = ['firstname', 'age'];
dan :
keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {});
// {firstname:'abd', age: 16}
Antwoord 9, autoriteit 2%
Ik heb een Object.filter()
gemaakt die niet alleen filtert op een functie, maar ook een reeks sleutels accepteert. Met de optionele derde parameter kunt u het filter omkeren.
Gegeven:
var foo = {
x: 1,
y: 0,
z: -1,
a: 'Hello',
b: 'World'
}
Array:
Object.filter(foo, ['z', 'a', 'b'], true);
Functie:
Object.filter(foo, function (key, value) {
return Ext.isString(value);
});
Code
Disclaimer: ik heb ervoor gekozen om Ext JS core te gebruiken voor de beknoptheid. Vond het niet nodig om typecontroles voor objecttypen te schrijven, omdat dit geen deel uitmaakte van de vraag.
// Helper function
function print(obj) {
document.getElementById('disp').innerHTML += JSON.stringify(obj, undefined, ' ') + '<br />';
console.log(obj);
}
Object.filter = function (obj, ignore, invert) {
let result = {}; // Returns a filtered copy of the original list
if (ignore === undefined) {
return obj;
}
invert = invert || false;
let not = function(condition, yes) { return yes ? !condition : condition; };
let 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))) {
result[key] = obj[key];
}
}
return result;
};
let foo = {
x: 1,
y: 0,
z: -1,
a: 'Hello',
b: 'World'
};
print(Object.filter(foo, ['z', 'a', 'b'], true));
print(Object.filter(foo, (key, value) => 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>
Antwoord 10
Mijn eigenzinnige oplossing:
function objFilter(obj, filter, nonstrict){
r = {}
if (!filter) return {}
if (typeof filter == 'string') return {[filter]: obj[filter]}
for (p in obj) {
if (typeof filter == 'object' && nonstrict && obj[p] == filter[p]) r[p] = obj[p]
else if (typeof filter == 'object' && !nonstrict && obj[p] === filter[p]) r[p] = obj[p]
else if (typeof filter == 'function'){ if (filter(obj[p],p,obj)) r[p] = obj[p]}
else if (filter.length && filter.includes(p)) r[p] = obj[p]
}
return r
}
Testgevallen:
obj = {a:1, b:2, c:3}
objFilter(obj, 'a') // returns: {a: 1}
objFilter(obj, ['a','b']) // returns: {a: 1, b: 2}
objFilter(obj, {a:1}) // returns: {a: 1}
objFilter(obj, {'a':'1'}, true) // returns: {a: 1}
objFilter(obj, (v,k,o) => v%2===1) // returns: {a: 1, c: 3}
https://gist.github.com/bernardoadc/872d5a174108823159d845cc5baba337
Antwoord 11
Als je Symbol
hebt eigenschappen in uw object, die ook moeten worden gefilterd, kunt u nietgebruiken: Object.keys
Object.entries
Object.fromEntries
, … omdat:
Symbol
-sleutels zijn geen opsombaar!
U kunt Reflect.ownKeys
en filtersleutels in reduce
Reflect.ownKeys(o).reduce((a, k) => allow.includes(k) && {...a, [k]: o[k]} || a, {});
(Open DevTools voor logoutput – Symbolen zijn niet ingelogd op Stackoverflow UI)
const bKey = Symbol('b_k');
const o = {
a: 1,
[bKey]: 'b',
c: [1, 3],
[Symbol.for('d')]: 'd'
};
const allow = ['a', bKey, Symbol.for('d')];
const z1 = Reflect.ownKeys(o).reduce((a, k) => allow.includes(k) && {...a, [k]: o[k]} || a, {});
console.log(z1); // {a: 1, Symbol(b_k): "b", Symbol(d): "d"}
console.log(bKey in z1) // true
console.log(Symbol.for('d') in z1) // true
Antwoord 12
Als u hetzelfde object wilt muteren in plaats van een nieuw te maken.
Het volgende voorbeeld verwijdert alle 0 of lege waarden:
const sev = { a: 1, b: 0, c: 3 };
const deleteKeysBy = (obj, predicate) =>
Object.keys(obj)
.forEach( (key) => {
if (predicate(obj[key])) {
delete(obj[key]);
}
});
deleteKeysBy(sev, val => !val);
Antwoord 13
Effen ES6:
var foo = {
bar: "Yes"
};
const res = Object.keys(foo).filter(i => foo[i] === 'Yes')
console.log(res)
// ["bar"]
Antwoord 14
Zoals iedereen al zei, rotzooi niet met prototypes. Schrijf in plaats daarvan gewoon een functie om dit te doen. Hier is mijn versie met lodash
:
import each from 'lodash/each';
import get from 'lodash/get';
const myFilteredResults = results => {
const filteredResults = [];
each(results, obj => {
// filter by whatever logic you want.
// sample example
const someBoolean = get(obj, 'some_boolean', '');
if (someBoolean) {
filteredResults.push(obj);
}
});
return filteredResults;
};
Antwoord 15
Ik gebruik dit wanneer ik het nodig heb:
const filterObject = (obj, condition) => {
const filteredObj = {};
Object.keys(obj).map(key => {
if (condition(key)) {
dataFiltered[key] = obj[key];
}
});
return filteredObj;
}
Antwoord 16
In deze gevallen gebruik ik de jQuery $.map, die objecten aankan. Zoals vermeld in andere antwoorden, is het geen goede gewoonte om native prototypes te wijzigen (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes)
Hieronder ziet u een voorbeeld van filteren door een eigenschap van uw object te controleren. Het retourneert het eigen object als uw voorwaarde waar is of retourneert undefined
als dat niet het geval is. De eigenschap undefined
zorgt ervoor dat dat record uit uw objectlijst verdwijnt;
$.map(yourObject, (el, index)=>{
return el.yourProperty ? el : undefined;
});