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检查)将打破,因为你添加的函数将是迭代的一部分。

其他回答

如何:

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

还是……

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

我已经创建了一个Object.filter(),它不仅通过一个函数进行筛选,而且还接受一个包含键的数组。可选的第三个参数将允许反转筛选器。

考虑到:

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

数组:

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

功能:

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

Code

免责声明:为了简洁起见,我选择使用Ext JS核心。我觉得没有必要为对象类型编写类型检查器,因为这不是问题的一部分。

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

首先,扩展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(过滤);

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

鉴于

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

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

然后:

keys.reduce((result, key) => ({ ...result, [key]: object[key] }), {});
// {firstname:'abd', age: 16}

/ /帮助 函数过滤器(对象,…键){ 返回键。Reduce ((result, key) =>({…结果,[key]:对象[key]}), {}); }; / /实例 Const person ={名:' abd',姓:'tm',年龄:16岁,学校:'insat'}; //期望只选择名字和年龄键 console.log ( Filter (person, 'firstname', 'age') )

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

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