从数组中删除所有对象的属性

249
我想从数组中的每个对象中删除“bad”属性。是否有比使用for循环并从每个对象中删除它更好的方法?
var array = [{"bad": "something", "good":"something"},{"bad":"something", "good":"something"},...];

for (var i = 0, len = array.length; i < len; i++) {
  delete array[i].bad;
}

感觉应该有一种方法可以使用 prototype,或者其他的什么东西。我不知道。有什么想法吗?


1
无论如何,其他方法都不能获得比线性O(n)更少的时间复杂度。无论你使用什么方法,都需要访问数组中的所有元素。 - Brian
1
@Bergi 我想知道他们是指PrototypeJS还是Array原型,dystroy举例说明了什么。 - Ian
我不确定在循环之前将数组长度存储在变量中是否明智。如果进行性能分析,您肯定会发现这样做不值得痛苦。 - Denys Séguret
@dystroy 除了再创建一个本地变量,还有什么“痛点”吗? - Ian
1
@ZackArgyle 是的,在一般情况下没有比这更快的了。 - Denys Séguret
显示剩余3条评论
19个回答

436

使用ES6,您可以解构每个对象以创建新的未命名属性的对象:

const newArray = array.map(({dropAttr1, dropAttr2, ...keepAttrs}) => keepAttrs)

55
针对最初的问题,可以这样写:const newArray = array.map(({ bad, ...item }) => item);意思是创建一个新数组newArray,使用map()方法遍历原始数组array中的每个元素,然后从每个元素中提取除了属性bad之外的属性并返回一个新的对象。 - dhilt
5
这非常推荐,因为它不会修改原始数组(不可变操作)。 - Pizzicato
3
这应该是被接受的答案,因为它返回一个新的数组,而不是覆盖现有的数组。 - user1275105
8
@ИгорТашевски .map(({ [prop]: _, ...keep }) => keep) @ИгорТашевски .map(({ [prop]: _, ...keep }) => keep) - Emile Bergeron
1
@Reid 是一个变量名,用于表示一个具有属性的对象,这些属性将被保留(不会被移除)。 - piotr_cz
显示剩余12条评论

185
唯一的其他方法是化妆,实际上就是循环。
例如:
array.forEach(function(v){ delete v.bad });

注意:

  • 如果你想兼容IE8,你需要为 forEach 使用 shim。由于你提到了 prototype,prototype.js 也 有一个 shim
  • delete 是最糟糕的"性能杀手"之一。经常使用它会破坏应用程序的性能。如果你真的想要删除一个属性,你无法避免使用它,但你通常可以将属性设置为undefined或者构建一个不包含该属性的新对象。

1
如果允许循环是“假”的一行代码,那么这种方法并没有比循环好多少:P for(var i = 0; i < array.length ) delete array[i].bad - Esailija
1
@Esailija 这要看情况。我喜欢使用 forEach,因为我觉得代码更加表达清晰(而且因为很久以前我就不再担心 IE 的问题了)。 - Denys Séguret
1
它们两个都没有以根本不同的方式表达“删除此数组中所有对象的错误属性”。forEach是通用的,本身语义上毫无意义,就像for循环一样。 - Esailija
1
@Esailija 我同意。这就是为什么我强调它是“表面的”。我的回答不清楚吗? - Denys Séguret
很遗憾。我会坚持使用for循环,因为它通常比forEach更快。而且,谁在乎IE8呢。感谢您的帮助。 - Zack Argyle
显示剩余6条评论

34

我更喜欢使用 map 方法来删除属性,然后返回新的数组项。

array.map(function(item) { 
    delete item.bad; 
    return item; 
});

25
注意,这会改变原始数组。 - piotr_cz
2
在这种情况下,不需要显式的 return 语句。 - Sandeep Kumar
7
array.forEach(v => delete v.bad); - Anthony Awuley

23

您可以按照此方式,更易读的方式进行操作,但不要预期由于未找到关键字而引发问题:

data.map((datum) => {
  return {
    'id':datum.id,
    'title':datum.login
  }
});

1
这正是我所需要的!我的对象大约有15个属性,而我只需要保留3个。 - RCW

20
const arr = [
  {id: 1, name: 'user1', test: 'abc'},
  {id: 2, name: 'user2', test: 'xyz'},
];

const newArr = arr.map(({test, ...rest}) => {
  return rest;
});

console.log(newArr);
// ️ [{id: 1, name: 'User1'},  {id: 2, name: 'User2'}]

我们传递给Array.map方法的函数将会对数组中的每个元素进行调用。

我们从每个对象中析取test属性,使用剩余运算符(...)获取对象的其余属性。

我们从函数中返回对象的其余属性,实际上是排除了test属性。

const arr = [
  {id: 1, name: 'Tom', test: 'abc'},
  {id: 2, name: 'Bob', test: 'xyz'},
];

arr.forEach(object => {
  delete object['test'];
});

console.log(arr);
// ️ [{id: 1, name: 'Tom'}, {id: 2, name: 'Bob'}]

它将 null 返回到数组。 - Mohamed Farouk
如果可能的话,请分享您的代码示例。这有助于理解问题。 - akshay_sushir

17

如果您使用underscore.js

var strippedRows = _.map(rows, function (row) {
    return _.omit(row, ['bad', 'anotherbad']);
});

据我所知,_.omit将在Lodash v5中被删除。 - Drenai

10

在我看来,这是最简单的选择。

array.map(({good}) => ({good}))

14
问题是关于移除不好的部分,而不是保留好的部分。如果你的对象有10个需要保留的字段和1个需要移除的字段,那么以上内容输入起来会变得很长。 - adrien

8

只有当你的对象相似时,才能使用原型来解决问题:

function Cons(g) { this.good = g; }
Cons.prototype.bad = "something common";
var array = [new Cons("something 1"), new Cons("something 2"), …];

但是这很简单(而且O(1)):
delete Cons.prototype.bad;

8

var array = [{"bad": "something", "good":"something"},{"bad":"something", "good":"something"}];

const cleanArray = array.map(item=>{
  delete item.bad
  return item
})
console.log(cleanArray)


3
ES6中最短的写法:
array.forEach(e => {delete e.someKey});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接