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>


当前回答

正如patrick已经说过的,这是一个坏主意,因为它几乎肯定会破坏任何第三方代码,你可能希望使用。

所有的库,如jquery或prototype将中断如果你扩展Object。原型,原因是在对象上的惰性迭代(没有hasOwnProperty检查)将打破,因为你添加的函数将是迭代的一部分。

其他回答

如果您愿意使用下划线或lodash,您可以使用pick(或与其相反的省略)。

来自underscore文档的例子:

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

或者使用回调(对于lodash,使用pickBy):

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

正如patrick已经说过的,这是一个坏主意,因为它几乎肯定会破坏任何第三方代码,你可能希望使用。

所有的库,如jquery或prototype将中断如果你扩展Object。原型,原因是在对象上的惰性迭代(没有hasOwnProperty检查)将打破,因为你添加的函数将是迭代的一部分。

如果您希望改变相同的对象,而不是创建一个新的对象。

下面的例子将删除所有0或空值:

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

如果你的对象中有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"}

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

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。