JavaScript:对象的filter()

发布于 2024-10-18 06:16:05 字数 1520 浏览 4 评论 0原文

如果我理解正确的话,ECMAScript 5 有 Array 类型的 filter() 原型,但没有 Object 类型。

如何在 JavaScript 中为 Object 实现 filter()

假设我有这个对象:

var foo = {
    bar: "Yes"
};

并且我想编写一个适用于 Objectfilter()

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>

ECMAScript 5 has the filter() prototype for Array types, but not Object types, if I understand correctly.

How would I implement a filter() for Objects in JavaScript?

Let's say I have this object:

var foo = {
    bar: "Yes"
};

And I want to write a filter() that works on 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;
};

This works when I use it in the following demo, but when I add it to my site that uses jQuery 1.5 and jQuery UI 1.8.9, I get JavaScript errors 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

一场信仰旅途 2024-10-25 06:16:05

首先,扩展对象被认为是不好的做法。原型。相反,将您的功能作为独立功能提供,或者如果您确实想扩展全局功能,请将其作为 Object 上的实用功能提供,就像已经有 Object.keysObject.assignObject.is、...等。

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

  1. 使用 reduceObject.keys
  2. As (1),结合 Object.assign
  3. 使用 map< /code> 和扩展语法而不是 reduce
  4. 使用 Object.entriesObject.fromEntries

1. 使用 reduceObject.keys

减少 Object.keys 实现所需的过滤器(使用 ES6 箭头语法):

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

请注意,在上面的代码中,谓词必须是包含条件(与OP使用的排除条件相反),以便它符合如何Array.prototype.filter 有效。

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

在上述解决方案中 逗号运算符用于reduce部分,以返回变异的res对象。当然,这可以写成两个语句而不是一个表达式,但后者更简洁。要在不使用逗号运算符的情况下执行此操作,您可以使用 Object.assign,它确实返回变异对象:

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

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

这里我们将 Object.assign 调用移出循环,因此它只执行一次,并将各个键作为单独的参数传递给它(使用 扩展语法):

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

4. 使用 Object.entriesObject.fromEntries

由于该解决方案将对象转换为中间数组,然后将其转换回普通对象,因此使使用 Object.entries< /a> (ES2017) 和相反的(即 从键/值对数组创建对象) href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries" rel="noreferrer">Object.fromEntries(ES2019)。

它导致了 Object 上的这个“one-liner”方法:

Object.filter = (obj, predicate) => 
                  Object.fromEntries(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);

此处谓词函数获取一个键/值对作为参数,这有点不同,但允许谓词函数的逻辑有更多可能性。

First of all, it's considered bad practice to extend Object.prototype. Instead, provide your feature as stand-alone function, or if you really want to extend a global, provide it as utility function on Object, just like there already are Object.keys, Object.assign, Object.is, ...etc.

I provide here several solutions:

  1. Using reduce and Object.keys
  2. As (1), in combination with Object.assign
  3. Using map and spread syntax instead of reduce
  4. Using Object.entries and Object.fromEntries

1. Using reduce and Object.keys

With reduce and Object.keys to implement the desired filter (using ES6 arrow syntax):

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

Note that in the above code predicate must be an inclusion condition (contrary to the exclusion condition the OP used), so that it is in line with how Array.prototype.filter works.

2. As (1), in combination with Object.assign

In the above solution the comma operator is used in the reduce part to return the mutated res object. This could of course be written as two statements instead of one expression, but the latter is more concise. To do it without the comma operator, you could use Object.assign instead, which does return the mutated object:

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

3. Using map and spread syntax instead of reduce

Here we move the Object.assign call out of the loop, so it is only made once, and pass it the individual keys as separate arguments (using the spread 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);

4. Using Object.entries and Object.fromEntries

As the solution translates the object to an intermediate array and then converts that back to a plain object, it would be useful to make use of Object.entries (ES2017) and the opposite (i.e. create an object from an array of key/value pairs) with Object.fromEntries (ES2019).

It leads to this "one-liner" method on Object:

Object.filter = (obj, predicate) => 
                  Object.fromEntries(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);

The predicate function gets a key/value pair as argument here, which is a bit different, but allows for more possibilities in the predicate function's logic.

千仐 2024-10-25 06:16:05

永远不要扩展Object.prototype

你的代码将会发生可怕的事情。事情会破裂。您正在扩展所有对象类型,包括对象文字。

这是您可以尝试的一个简单示例:

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

而是创建一个传递对象的函数。

Object.filter = function( obj, predicate) {
    let result = {}, key;

    for (key in obj) {
        if (obj.hasOwnProperty(key) && !predicate(obj[key])) {
            result[key] = obj[key];
        }
    }

    return result;
};

Never ever extend Object.prototype.

Horrible things will happen to your code. Things will break. You're extending all object types, including object literals.

Here's a quick example you can try:

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

Instead create a function that you pass the object.

Object.filter = function( obj, predicate) {
    let result = {}, key;

    for (key in obj) {
        if (obj.hasOwnProperty(key) && !predicate(obj[key])) {
            result[key] = obj[key];
        }
    }

    return result;
};
↙温凉少女 2024-10-25 06:16:05

从 2020 年开始,Vanilla JS 中的解决方案。


let romNumbers={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}

您可以按键过滤 romNumbers 对象:

const filteredByKey = Object.fromEntries(
    Object.entries(romNumbers).filter(([key, value]) => key === 'I') )
// filteredByKey = {I: 1} 

或按值过滤 romNumbers 对象:

 const filteredByValue = Object.fromEntries(
    Object.entries(romNumbers).filter(([key, value]) => value === 5) )
 // filteredByValue = {V: 5} 

Solution in Vanilla JS from year 2020.


let romNumbers={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}

You can filter romNumbers object by key:

const filteredByKey = Object.fromEntries(
    Object.entries(romNumbers).filter(([key, value]) => key === 'I') )
// filteredByKey = {I: 1} 

Or filter romNumbers object by value:

 const filteredByValue = Object.fromEntries(
    Object.entries(romNumbers).filter(([key, value]) => value === 5) )
 // filteredByValue = {V: 5} 
小傻瓜 2024-10-25 06:16:05

如果您愿意使用下划线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}

If you're willing to use underscore or lodash, you can use pick (or its opposite, omit).

Examples from underscore's docs:

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

Or with a callback (for lodash, use pickBy):

_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
// {age: 50}
甜中书 2024-10-25 06:16:05

ES6 方法...

假设您有下面这个对象:

const developers = {
  1: {
   id: 1,
   name: "Brendan", 
   family: "Eich"
  },
  2: {
   id: 2,
   name: "John", 
   family: "Resig"
  },  
  3: {
   id: 3,
   name: "Alireza", 
   family: "Dezfoolian"
 }
};

创建一个函数:

const filterObject = (obj, filter, filterValue) => 
   Object.keys(obj).reduce((acc, val) => 
   (obj[val][filter] === filterValue ? acc : {
       ...acc,
       [val]: obj[val]
   }                                        
), {});

并调用它:

filterObject(developers, "name", "Alireza");

并且将返回

{
  1: {
  id: 1,
  name: "Brendan", 
  family: "Eich"
  },
  2: {
   id: 2,
   name: "John", 
   family: "Resig"
  }
}

ES6 approach...

Imagine you have this object below:

const developers = {
  1: {
   id: 1,
   name: "Brendan", 
   family: "Eich"
  },
  2: {
   id: 2,
   name: "John", 
   family: "Resig"
  },  
  3: {
   id: 3,
   name: "Alireza", 
   family: "Dezfoolian"
 }
};

Create a function:

const filterObject = (obj, filter, filterValue) => 
   Object.keys(obj).reduce((acc, val) => 
   (obj[val][filter] === filterValue ? acc : {
       ...acc,
       [val]: obj[val]
   }                                        
), {});

And call it:

filterObject(developers, "name", "Alireza");

and will return:

{
  1: {
  id: 1,
  name: "Brendan", 
  family: "Eich"
  },
  2: {
   id: 2,
   name: "John", 
   family: "Resig"
  }
}
东走西顾 2024-10-25 06:16:05

那么给出

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

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

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

Given

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

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

then :

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

此刻的回忆 2024-10-25 06:16:05

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

如果您扩展Object.prototype,所有像jquery或prototype这样的库都会中断,原因是对象上的惰性迭代(没有hasOwnProperty检查)将会中断,因为您添加的函数将中断成为迭代的一部分。

As patrick already stated this is a bad idea, as it will almost certainly break any 3rd party code you could ever wish to use.

All libraries like jquery or prototype will break if you extend Object.prototype, the reason being that lazy iteration over objects (without hasOwnProperty checks) will break since the functions you add will be part of the iteration.

佼人 2024-10-25 06:16:05

普通 ES6:

var foo = {
    bar: "Yes"
};

const res = Object.keys(foo).filter(i => foo[i] === 'Yes')

console.log(res)
// ["bar"]

Plain ES6:

var foo = {
    bar: "Yes"
};

const res = Object.keys(foo).filter(i => foo[i] === 'Yes')

console.log(res)
// ["bar"]
栖迟 2024-10-25 06:16:05

怎么样:

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

How about:

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

Or...

function filterObj(keys, obj) {
  const newObj = {};
  Object.keys(obj).forEach(key => {
    if (keys.includes(key)) {
      newObj[key] = obj[key];
    }
  });
  return newObj;
}
温柔一刀 2024-10-25 06:16:05

我创建了一个 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);
});

代码

免责声明:为了简洁起见,我选择使用 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>

I have created an Object.filter() which does not only filter by a function, but also accepts an array of keys to include. The optional third parameter will allow you to invert the filter.

Given:

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

Array:

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

Function:

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

Code

Disclaimer: I chose to use Ext JS core for brevity. Did not feel it was necessary to write type checkers for object types as it was not part of the question.

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

葵雨 2024-10-25 06:16:05
    var foo = {
    bar: "Yes",
    pipe: "No"
};

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

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

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

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

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

羁〃客ぐ 2024-10-25 06:16:05

我固执己见的解决

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

My opinionated solution:

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
}

Test cases:

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

心清如水 2024-10-25 06:16:05

如果您的文件中有 Symbol 属性对象,也应该被过滤,你可以使用:Object.keys Object.entries Object.fromEntries,...因为:

Symbol 键不是 可枚举 !

您可以使用 Reflect.ownKeys< /code>reduce

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

(打开 DevTools 进行日志输出 - 符号未记录在 Stackoverflow UI 上)

const bKey = Symbol('b_k');
const o = {
    a:                 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, Symbol(b_k): "b", Symbol(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() 函数中,可以传递可选的 target 对象

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

If you have Symbol properties in your object, that should be filtered too, you can not use: Object.keys Object.entries Object.fromEntries, ... because:

Symbol keys are not enumerable !

You could use Reflect.ownKeys and filter keys in reduce

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

(Open DevTools for log output - Symbols are not logged on Stackoverflow UI)

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

This is equal to this

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

Wrapped in a filter() function, an optional target object could be passed

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"}
慈悲佛祖 2024-10-25 06:16:05

您还可以执行类似的操作,在其中过滤条目以查找提供的键并返回值

   let func = function(items){
      let val
      Object.entries(this.items).map(k => {
        if(k[0]===kind){
         val = k[1]
        }
      })
      return val
   }

You could also do something like this where you are filtering on the entries to find the key provided and return the value

   let func = function(items){
      let val
      Object.entries(this.items).map(k => {
        if(k[0]===kind){
         val = k[1]
        }
      })
      return val
   }
友欢 2024-10-25 06:16:05

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

以下示例将删除所有 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);

If you wish to mutate the same object rather than create a new one.

The following example will delete all 0 or empty values:

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);
标点 2024-10-25 06:16:05

我只是想添加我的做法,因为它可以节省我创建额外的函数,我认为更干净,而且我没有看到这个答案:

let object = {a: 1, b: 2, c: 3};
[object].map(({a,c}) => ({a,c}))[0]; // {a:1, c:2}

最酷的是它也适用于对象数组:

let object2 = {a: 4, b: 5, c: 6, d: 7};
[object, object2].map(({a,b,c,d}) => ({a,c})); //[{"a":1,"c":3},{"a":4,"c":6}]
[object, object2].map(({a,d}) => ({a,d})); //[{"a":1,"d":undefined},{"a":4,"d":7}]

I just wanted to add the way that I do it because it saves me creating extra functions, I think is cleaner and I didn't see this answer:

let object = {a: 1, b: 2, c: 3};
[object].map(({a,c}) => ({a,c}))[0]; // {a:1, c:2}

The cool thing is that also works on arrays of objects:

let object2 = {a: 4, b: 5, c: 6, d: 7};
[object, object2].map(({a,b,c,d}) => ({a,c})); //[{"a":1,"c":3},{"a":4,"c":6}]
[object, object2].map(({a,d}) => ({a,d})); //[{"a":1,"d":undefined},{"a":4,"d":7}]
眼眸 2024-10-25 06:16:05

正如大家所说,不要搞砸原型。相反,只需编写一个函数即可执行此操作。这是我使用 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;
};

Like everyone said, do not screw around with prototype. Instead, simply write a function to do so. Here is my version with 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;
};
旧伤还要旧人安 2024-10-25 06:16:05

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

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,在这种情况下使用array.includes而不是set.has

If you don't need the original object, this is a simple, very boring answer that doesn't waste memory:

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]
    }
  })
}

If you're only filtering a small number of objects, and your objects don't have many keys, you might not want to bother with constructing a Set, in which case use array.includes instead of set.has.

余生共白头 2024-10-25 06:16:05

您可以使用 Lodash 的 _.omit() 函数来实现此目的,该函数会创建一个不包括指定键的新对象。具体操作方法如下:

const _ = require('lodash');

const obj = { foo: 1, bar: 2 };
const filteredObj = _.omit(obj, 'bar');

console.log(filteredObj); // Output: { foo: 1 }

在此代码中,_.omit(obj, 'bar') 创建一个新对象,从 中排除键 'bar' obj 对象,并且 filteredObj 将包含 { foo: 1 }

You can achieve this using Lodash's _.omit() function, which creates a new object excluding the specified key. Here's how you can do it:

const _ = require('lodash');

const obj = { foo: 1, bar: 2 };
const filteredObj = _.omit(obj, 'bar');

console.log(filteredObj); // Output: { foo: 1 }

In this code, _.omit(obj, 'bar') creates a new object excluding the key 'bar' from the obj object, and filteredObj will contain { foo: 1 }.

夏了南城 2024-10-25 06:16:05

在这些情况下,我使用 jquery $.map,它可以处理对象。正如其他答案中提到的,更改本机原型并不是一个好的做法(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes

下面是仅通过检查对象的某些属性进行过滤的示例。如果您的条件为真,它会返回自己的对象;如果条件不为真,它会返回undefinedundefined 属性将使该记录从您的对象列表中消失;

$.map(yourObject, (el, index)=>{
    return el.yourProperty ? el : undefined;
});

In these cases I use the jquery $.map, which can handle objects. As mentioned on other answers, it's not a good practice to change native prototypes (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Bad_practice_Extension_of_native_prototypes)

Below is an example of filtering just by checking some property of your object. It returns the own object if your condition is true or returns undefined if not. The undefined property will make that record disappear from your object list;

$.map(yourObject, (el, index)=>{
    return el.yourProperty ? el : undefined;
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文