Pertanyaan JavaScript: filter () untuk Objek


ECMAScript 5 memiliki filter() prototipe untuk Array jenis, tetapi tidak Object jenis, jika saya mengerti dengan benar.

Bagaimana saya menerapkan filter() untuk Objectdi JavaScript?

Katakanlah saya memiliki objek ini:

var foo = {
    bar: "Yes"
};

Dan saya ingin menulis filter() yang berfungsi 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;
};

Ini berfungsi ketika saya menggunakannya di demo berikut, tetapi ketika saya menambahkannya ke situs saya yang menggunakan jQuery 1.5 dan jQuery UI 1.8.9, saya mendapatkan kesalahan JavaScript di 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


asal


Jawaban:


Jangan pernah memperpanjang Object.prototype.

Hal-hal yang mengerikan akan terjadi pada kode Anda. Semuanya akan hancur. Anda memperpanjang semua jenis objek, termasuk literal objek.

Berikut contoh cepat yang dapat Anda coba:

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

Sebaliknya, buat fungsi yang Anda lewati objek.

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



Pertama-tama, itu dianggap praktik buruk untuk diperpanjang Object.prototype. Sebagai gantinya, sediakan fitur Anda sebagai fungsi utilitas Object, seperti yang sudah ada Object.keys, Object.assign, Object.is, ... dll.

Kamu dapat memakai reduce dan Object.keys untuk mengimplementasikan filter yang diinginkan (menggunakan ES6 panah sintaksis):

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

Perhatikan bahwa dalam kode di atas predicate harus menjadi penyertaan kondisi (bertentangan dengan pengecualian kondisi OP yang digunakan), sehingga sesuai dengan caranya Array.prototype.filter bekerja.

Dengan Object.assign

Dalam solusi di atas operator koma digunakan dalam reduce bagian untuk mengembalikan yang dimutasi res obyek. Ini tentu saja dapat ditulis sebagai dua pernyataan, bukan satu ekspresi, tetapi yang terakhir lebih ringkas. Untuk melakukannya tanpa operator koma, Anda bisa menggunakannya Object.assign sebaliknya, yang mana tidak kembalikan objek yang dimutasi:

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

Menggunakan sintaks spread

Di sini kita memindahkan Object.assign panggilan keluar dari loop, sehingga hanya dilakukan sekali, dan menyebarkannya kunci individu sebagai argumen terpisah (menggunakan sebarkan sintaksis):

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

Fungsi pemisahan: kustom Object.from

Ketika solusinya menerjemahkan objek ke array menengah dan kemudian mengkonversikannya kembali ke objek biasa, akan berguna untuk memanfaatkan Object.entries (ES2017) dan untuk membuat metode yang berlawanan (mis. membuat objek dari array pasangan kunci / nilai).

Ini mengarah ke dua metode "satu-liner" ini 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);

Fungsi predikat mendapat pasangan kunci / nilai sebagai argumen di sini, yang sedikit berbeda, tetapi memungkinkan untuk lebih banyak kemungkinan dalam logika fungsi predikat.


123
2018-06-03 13:46



Jika Anda bersedia menggunakannya menggarisbawahi atau lodash, Kamu dapat memakai pick (atau sebaliknya, omit).

Contoh dari dokumen underscore:

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

Atau dengan panggilan balik (untuk lodash, gunakan pickBy):

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

14
2017-10-05 11:40



Sebagai patrick sudah menyatakan ini adalah ide yang buruk, karena hampir pasti akan mematahkan kode pihak ke-3 yang Anda inginkan untuk digunakan.

Semua perpustakaan seperti jquery atau prototipe akan rusak jika Anda memperpanjang Object.prototype, alasannya adalah bahwa iterasi malas atas objek (tanpa hasOwnProperty pemeriksaan) akan rusak karena fungsi yang Anda tambahkan akan menjadi bagian dari iterasi.


2
2018-02-21 22:47



Saya telah membuat sebuah Object.filter() yang tidak hanya memfilter berdasarkan fungsi, tetapi juga menerima serangkaian kunci untuk disertakan. Parameter ketiga opsional akan memungkinkan Anda membalikkan filter.

Diberikan:

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

Larik:

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

Fungsi:

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

Kode

Penolakan: Saya memilih untuk menggunakan inti Ext JS untuk keringkasan. Tidak merasa perlu untuk menulis tipe pemeriksa untuk jenis objek karena itu bukan bagian dari pertanyaan.


1
2017-12-31 17:31



Bagaimana tentang:

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

Atau...

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



Diberikan

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

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

kemudian :

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