Frage JavaScript: filter () für Objekte


ECMAScript 5 hat die filter() Prototyp für Array Typen, aber nicht Object Typen, wenn ich das richtig verstehe.

Wie würde ich ein filter() zum Objects in JavaScript?

Sagen wir, ich habe dieses Objekt:

var foo = {
    bar: "Yes"
};

Und ich möchte ein schreiben filter() das funktioniert 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;
};

Das funktioniert, wenn ich es in der folgenden Demo verwende, aber wenn ich es meiner Site hinzufüge, die jQuery 1.5 und jQuery UI 1.8.9 verwendet, erhalte ich JavaScript-Fehler 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
}
<div id="disp"></div>


75
2018-02-21 22:42


Ursprung


Antworten:


Niemals verlängern Object.prototype.

Ihrem Code passieren entsetzliche Dinge. Die Dinge werden brechen. Du verlängerst dich alle Objekttypen, einschließlich Objektliteralen.

Hier ist ein kurzes Beispiel, das Sie versuchen können:

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

Erstellen Sie stattdessen eine Funktion, die Sie das Objekt übergeben.

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

111
2018-02-21 22:43



Als erstes, Es ist eine schlechte Übung, sich auszudehnen Object.prototype. Stellen Sie stattdessen Ihre Funktion als Dienstprogrammfunktion bereit Object, so wie es schon ist Object.keys, Object.assign, Object.is, ...etc.

Sie können verwenden reduce und Object.keys um den gewünschten Filter zu implementieren (mit ES6 Pfeilsyntax):

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

Beachten Sie, dass in dem obigen Code predicate muss ein sein Aufnahme Bedingung (im Gegensatz zu den Ausschluss Condition das OP verwendet), so dass es im Einklang mit wie Array.prototype.filter funktioniert.

Mit Object.assign

In der obigen Lösung der Komma-Operator wird in der verwendet reduce Teil, um das mutierte zurückzugeben res Objekt. Dies könnte natürlich als zwei Aussagen anstelle eines Ausdrucks geschrieben werden, aber letzteres ist prägnanter. Um es ohne den Komma-Operator zu tun, könnten Sie verwenden Object.assign stattdessen, welche tut gib das mutierte Objekt zurück:

Object.filter = (obj, predicate) => 
    Object.keys(obj)
          .filter( key => predicate(obj[key]) )
          .reduce( (res, key) => Object.assign(res, { [key]: obj[key] }), {} );

// Example use:
var scores = {
    John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1); 
console.log(filtered);

Verwenden der Spreizsyntax

Hier bewegen wir die Object.assign Aufruf aus der Schleife, so dass es nur einmal gemacht wird, und übergeben Sie die einzelnen Schlüssel als separate Argumente (mit der verbreite Syntax):

Object.filter = (obj, predicate) => 
    Object.assign(...Object.keys(obj)
                    .filter( key => predicate(obj[key]) )
                    .map( key => ({ [key]: obj[key] }) ) );

// Example use:
var scores = {
    John: 2, Sarah: 3, Janet: 1
};
var filtered = Object.filter(scores, score => score > 1); 
console.log(filtered);

Aufteilungsfunktionalität: benutzerdefiniert Object.from

Wenn die Lösung das Objekt in ein intermediäres Array umwandelt und dieses dann zurück in ein einfaches Objekt konvertiert, wäre es nützlich, davon Gebrauch zu machen Object.entries (ES2017) und eine Methode zu entwickeln, die das Gegenteil tut (d. H. Erstellen Sie ein Objekt aus einem Array von Schlüssel / Wert-Paaren).

Es führt zu diesen beiden "One-Liner" -Methoden weiter Object:

Object.from = arr => Object.assign(...arr.map( ([k, v]) => ({[k]: v}) ));
Object.filter = (obj, predicate) => Object.from(Object.entries(obj).filter(predicate));

// Example use:
var scores = {
    John: 2, Sarah: 3, Janet: 1
};

var filtered = Object.filter(scores, ([name, score]) => score > 1); 
console.log(filtered);

Die Prädikatfunktion erhält hier ein Schlüssel / Wert-Paar als Argument, das ein bisschen anders ist, aber mehr Möglichkeiten in der Logik der Prädikatfunktion erlaubt.


123
2018-06-03 13:46



Wenn Sie bereit sind zu verwenden unterstreichen oder lodashkannst du benutzen pick (oder sein Gegenteil, omit).

Beispiele aus der Unterstrich-Dokumentation:

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

Oder mit einem Rückruf (für lodash, benutzen pickBy):

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

14
2017-10-05 11:40



Wie Patrick schon gesagt hat, ist dies eine schlechte Idee, da es mit Sicherheit einen 3rd Party Code bricht, den Sie jemals benutzen könnten.

Alle Bibliotheken wie jQuery oder Prototyp werden bei der Erweiterung unterbrochen Object.prototypeDer Grund dafür ist die faule Iteration über Objekte (ohne hasOwnProperty checks) wird abgebrochen, da die hinzugefügten Funktionen Teil der Iteration sind.


2
2018-02-21 22:47



Ich habe eine erstellt Object.filter() Diese Funktion filtert nicht nur nach einer Funktion, sondern akzeptiert auch eine Reihe von einzuschließenden Schlüsseln. Mit dem optionalen dritten Parameter können Sie den Filter invertieren.

Gegeben:

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

Array:

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

Funktion:

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

Code

Haftungsausschluss: Ich wählte den Ext JS-Kern der Kürze halber. Ich hielt es nicht für notwendig, Typüberprüfer für Objekttypen zu schreiben, da dies nicht Teil der Frage war.


1
2017-12-31 17:31



Wie wäre es mit:

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

Oder...

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

0
2018-05-20 17:33



Gegeben

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

keys = ['firstname', 'age'];

dann :

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


0
2017-11-12 11:17