JavaScript: filter() voor objecten

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 Objects in JavaScript implementeren?

Stel dat ik dit object heb:

var foo = {
    bar: "Yes"
};

En ik wil een filter()schrijven die werkt op Objects:

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:

  1. Gebruik reduceen Object.keys
  2. Als (1), in combinatie met Object.assign
  3. Gebruik mapen spreid syntaxis in plaats van reduce
  4. Gebruik Object.entriesen Object.fromEntries

1. Gebruik reduceen Object.keys

Met reduceen Object.keysom 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 romNumbersobject 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.prototypeuitbreidt, 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 Symbolhebt eigenschappen in uw object, die ook moeten worden gefilterd, kunt u nietgebruiken: Object.keysObject.entriesObject.fromEntries, … omdat:

Symbol-sleutels zijn geen opsombaar!

U kunt Reflect.ownKeysen 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 undefinedals dat niet het geval is. De eigenschap undefinedzorgt ervoor dat dat record uit uw objectlijst verdwijnt;

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

2 × 2 =

Other episodes