ECMAScript 5有数组类型的filter()原型,但没有对象类型,如果我理解正确的话。

我如何在JavaScript中实现对象的过滤器()?

假设我有这个对象:

var foo = {
    bar: "Yes"
};

我想写一个过滤器(),工作在对象:

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的站点时,我在FireBug中得到JavaScript错误。

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>


当前回答

    var foo = {
    bar: "Yes",
    pipe: "No"
};

const ret =  Object.entries(foo).filter(([key, value])=> value === 'Yes');

https://masteringjs.io/tutorials/fundamentals/filter-object

其他回答

如果你不需要原始对象,这是一个简单的,非常无聊的答案,不浪费内存:

const obj = {'a': 'want this', 'b': 'want this too', 'x': 'remove this'}
const keep = new Set(['a', 'b', 'c'])

function filterObject(obj, keep) {
  Object.keys(obj).forEach(key => {
    if (!keep.has(key)) {
      delete obj[key]
    }
  })
}

如果只过滤少量对象,并且对象没有很多键,则可能不想构造Set,在这种情况下使用数组。Includes而不是set.has。

就像所有人说的,不要在原型上做文章。相反,只需编写一个函数来执行此操作。以下是我使用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;
};

首先,扩展Object.prototype被认为是不好的做法。相反,将你的特性作为独立的函数提供,或者如果你真的想扩展一个全局函数,将它作为Object上的实用函数提供,就像已经有Object一样。钥匙,对象。分配对象。是,等。

我在这里提供几个解决方案:

使用reduce和object .key 如(1),结合Object.assign 使用map和spread语法代替reduce 使用对象。entry和Object.fromEntries

1. 使用reduce和object .key

用reduce和Object。键来实现所需的过滤器(使用ES6箭头语法):

对象。Filter = (obj, predicate) => 种(obj) .filter(key => predicate(obj[key])) .reduce ((res,关键)= > (res(例子)= obj(例子),res), {}); //示例: Var分数= { 约翰:2,萨拉:3,珍妮特:1 }; var filtered =对象。Filter (scores, score => score > 1); console.log(过滤);

注意,在上面的代码中,谓词必须是一个包含条件(与OP使用的排除条件相反),以便与Array.prototype.filter的工作方式一致。

2. 如(1),结合Object.assign

在上面的解决方案中,逗号操作符用于reduce部分以返回变化后的res对象。这当然可以写成两个语句而不是一个表达式,但后者更简洁。如果不使用逗号操作符,可以使用Object。而是赋值,这将返回突变的对象:

对象。Filter = (obj, predicate) => 种(obj) .filter(key => predicate(obj[key])) .reduce((res, key) =>对象。赋值(res, {[key]: obj[key]}), {}); //示例: Var分数= { 约翰:2,萨拉:3,珍妮特:1 }; var filtered =对象。Filter (scores, score => score > 1); console.log(过滤);

3.使用map和spread语法代替reduce

这里我们移动对象。将赋值调用移出循环,因此只执行一次,并将各个键作为单独的参数传递给它(使用spread语法):

对象。Filter = (obj, predicate) => Object.assign(…种(obj) .filter(key => predicate(obj[key])) .map(key => ({[key]: obj[key]}))); //示例: Var分数= { 约翰:2,萨拉:3,珍妮特:1 }; var filtered =对象。Filter (scores, score => score > 1); console.log(过滤);

4. 使用对象。entry和Object.fromEntries

由于解决方案将对象转换为中间数组,然后将其转换回普通对象,因此使用object会很有用。entry (ES2017)和object . fromentries (ES2019)的相反(即从键/值对数组创建对象)。

它导致Object上的“一行”方法:

对象。Filter = (obj, predicate) => Object.fromEntries (Object.entries (obj) .filter(谓词)); //示例: Var分数= { 约翰:2,萨拉:3,珍妮特:1 }; var filtered =对象。Filter (scores, ([name, score]) => score > 1); console.log(过滤);

断言函数在这里获得一个键/值对作为参数,这有点不同,但在断言函数的逻辑中允许更多的可能性。

如果你的对象中有Symbol属性,那也应该被过滤,你不能使用:object。键对象。Object.fromEntries,…因为:

符号键是不可枚举的!

你可以使用Reflect。reduce中的ownKeys和filter key

Reflect.ownKeys(o).reduce((a, k) => allow.includes(k) && {...a, [k]: o[k]} || a, {});

(打开DevTools输出日志- Stackoverflow界面上不记录符号)

const bKey =符号('b_k'); Const o = { 一个 : 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,符号(b_k): "b",符号(d): "d"} console.log(bKey in z1) // true console.log(Symbol.for('d') in z1) // true

这个等于这个

const z2 = Reflect.ownKeys(o).reduce((a, k) => allow.includes(k) && Object.assign(a, {[k]: o[k]}) || a, {});
const z3 = Reflect.ownKeys(o).reduce((a, k) => allow.includes(k) && Object.defineProperty(a, k, {value: o[k]}) || a, {});

console.log(z2); // {a: 1, Symbol(b_k): "b", Symbol(d): "d"}
console.log(z3); // {a: 1, Symbol(b_k): "b", Symbol(d): "d"}

在filter()函数中,可以传递一个可选的目标对象

const filter = (o, allow, t = {}) => Reflect.ownKeys(o).reduce(
    (a, k) => allow.includes(k) && {...a, [k]: o[k]} || a, 
    t
);

console.log(filter(o, allow));           // {a: 1, Symbol(b_k): "b", Symbol(d): "d"}
console.log(filter(o, allow, {e: 'e'})); // {a: 1, e: "e", Symbol(b_k): "b", Symbol(d): "d"}

我的观点是:

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
}

测试用例:

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