在 ES6 中按键过滤对象属性

IT技术 javascript ecmascript-6 filter
2021-02-04 16:43:07

假设我有一个对象:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

我想通过过滤上面的对象来创建另一个对象,所以我有类似的东西。

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }

我正在寻找一种使用 Es6 完成此操作的干净方法,因此我可以使用扩展运算符。

6个回答

如果您有一个允许值列表,您可以使用以下方法轻松地将它们保留在对象中:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    obj[key] = raw[key];
    return obj;
  }, {});

console.log(filtered);

这使用:

  1. Object.keys列出raw(原始数据)中的所有属性,然后
  2. Array.prototype.filter 选择存在于允许列表中的键,使用
    1. Array.prototype.includes 确保他们在场
  3. Array.prototype.reduce 构建一个仅具有允许属性的新对象。

这将使用允许的属性制作一个浅拷贝(但不会复制属性本身)。

您还可以使用对象扩展运算符来创建一系列对象而不改变它们(感谢rjerue 提到这一点):

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    return {
      ...obj,
      [key]: raw[key]
    };
  }, {});

console.log(filtered);

出于琐事的目的,如果您想从原始数据中删除不需要的字段(我建议这样做,因为它涉及一些丑陋的突变),您可以includes像这样反转检查:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

Object.keys(raw)
  .filter(key => !allowed.includes(key))
  .forEach(key => delete raw[key]);

console.log(raw);

我包含这个例子是为了展示一个基于突变的解决方案,但我不建议使用它。

谢谢,效果很好。我还通过使用“解构语法”找到了一种方法。IE : const {item1,item3} = raw const newObject = {item1,item3}
2021-03-19 16:43:07
如果您想以不可变的方式进行缩减,您还可以用 return { ...obj, [key]: raw[key] } 替换函数内容
2021-03-20 16:43:07
快速警告:Array.prototype.includes不是 ES6 的一部分。它是在 ECMAScript 2016 (ES7) 中引入的。
2021-03-21 16:43:07
我不能投票!使用 filter 和 reduce 而不是从 for 循环构造另一个对象做得很好。真棒,你明确地分离了不可变和可变版本。+1
2021-03-29 16:43:07
解构会工作(很好),但纯粹是编译时。你不能让它成为一个动态的属性列表或提供任何复杂的规则(例如,一个循环可以附加验证回调)。
2021-04-02 16:43:07

如果你都OK使用ES6语法,我发现,最干净的方式来做到这一点,因为注意到这里这里是:

const data = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const { item2, ...newData } = data;

现在,newData包含:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

或者,如果您将密钥存储为字符串:

const key = 'item2';
const { [key]: _, ...newData } = data;

在后一种情况下,[key]转换为,item2但由于您使用的是const赋值,因此需要为赋值指定一个名称。_表示丢弃值。

更普遍:

const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...

这不仅将您的操作简化为单行操作,而且还不需要您知道其他键是什么(您想要保留的键)。

一个简单的效用函数如下所示:

function removePropFromObject(obj, prop) {
  const { [prop]: _, ...rest } = obj
  return { ...rest }
}
@yhabib_没关系,它只是一个变量名,您可以将其重命名为您想要的任何名称
2021-03-13 16:43:07
_代表一个扔掉的value”这哪里来的?我第一次看到
2021-03-26 16:43:07
@Gerrat 我不认为通用的解决方案是微不足道的单行。为此,我将使用 lodash 的omit函数:lodash.com/docs/4.17.10#omit或此处给出的其他解决方案之一。
2021-03-30 16:43:07
我相信这是 JS 社区采用的约定。An_只是一个可以在 JS 中使用的有效变量名,但由于它几乎是无名的,如果您想传达意图,它真的不应该以这种方式使用。因此,它已被用作表示您不关心的变量的一种方式。这是关于它的进一步讨论:stackoverflow.com/questions/11406823/...
2021-04-02 16:43:07
这比接受的答案更整洁,避免了使用 Object.keys() 创建新数组的开销,以及使用filterand迭代数组的开销reduce
2021-04-05 16:43:07

你能找到的最干净的方法是使用Lodash#pick

const _ = require('lodash');

const allowed = ['item1', 'item3'];

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

const filteredObj = _.pick(obj, allowed)
需要指出的是,必须在运行时下载额外的项目依赖项。
2021-03-17 16:43:07
如果您使用 Ramda,还有 ramda.pick !ramdajs.com/docs/#pick
2021-04-05 16:43:07
_.omit(obj, ["item2"]) - lodash.omit 与 lodash.pick 相反
2021-04-08 16:43:07

之前没有说过什么,而是将一些答案与一般的 ES6 答案结合起来:

const raw = {
  item1: { key: 'sdfd', value: 'sdfd' },
  item2: { key: 'sdfd', value: 'sdfd' },
  item3: { key: 'sdfd', value: 'sdfd' }
};

const filteredKeys = ['item1', 'item3'];

const filtered = filteredKeys
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});

console.log(filtered);

这是一个比其他解决方案更简单、更高效的解决方案;)
2021-04-10 16:43:07

您现在可以使用Object.fromEntries方法(检查浏览器支持)使其更短更简单

const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };

const allowed = ['item1', 'item3'];

const filtered = Object.fromEntries(
   Object.entries(raw).filter(
      ([key, val])=>allowed.includes(key)
   )
);

阅读更多关于:Object.fromEntries

作为记录。使用Object.fromEntrieswith 时Typescript确保"lib": ["ES2019"]设置在tsconfig.json
2021-03-14 16:43:07
这是我现在认为最好的方法。比减少更直观。
2021-03-25 16:43:07