如何在JavaScript中从对象中省略特定属性

125

有没有一种简洁的方法,可以返回一个新对象,该对象不包含原始对象中包含的某些属性,而不必使用类似于lodash的东西?


代码?我建议创建一个新的匿名类型,传入你想要保留的内容。 - Edward
这里曾经有一个类似的问题:https://dev59.com/T1sW5IYBdhLWcg3wsY5P - gabesoft
6
可能是clone a js object except for one key的重复问题。 - gyre
18个回答

228
const { bar, baz, ...qux } = foo

现在,您的对象 qux 具有除 barbaz 之外的 foo 的所有属性。


4
请记住,这不会克隆对象。更新 qux 中的任何值都将更新 foo 中的值。JavaScript 对象是按引用传递的。 - Miroslav Glamuzina
30
@MiroslavGlamuzina 这不正确。如果你改变qux中的一个值,那么foo的值将不会更新。然而,如果qux的属性值是一个对象,并且你改变了该对象中的某些内容,那么foo中相应属性引用的对象也会被更改。 - Steven Oxley
只是一个小提示,在Chrome浏览器中(截至版本87.0.4280.141),这种方式不能用于带引号的属性名。我不知道其他环境是否也是如此:const { "bar", 'baz', ...qux } = foo - Sledge
@Sledge 你的一些键被引用了,这可能就是原因。 - surj
我认为这不是一个好的解决方案,因为它会产生创建新变量的副作用。如果你试图省略的任何属性恰好与预先存在的常量或变量匹配,你将会得到错误或意外行为。例如:const x = "Anything"; const obj = { x: "Foo", y:"Bar"}; const {x, ...no_x} = obj; - Lovethenakedgun
2
要选择“字符串”字段,您可以使用以下语法: const { ["bar"]:bar, ["baz"]:bas, ...qux } = foo 如果您有 const objKey = "bar";,则可以使用以下语法: const { [${objKey}]:bar, ["baz"]:bas, ...qux } = foo - MadaShindeInai

54

在现代环境中,您可以使用此代码片段:

function omit(key, obj) {
  const { [key]: omitted, ...rest } = obj;
  return rest;
}

4
“modern environments”的意思是,如果您正在发布未经转译的代码,则可以在93%的浏览器上运行。请在https://caniuse.com/mdn-javascript_operators_spread_spread_in_destructuring中查看完整的兼容性信息。 - Dawson B
1
谁会发布未编译的代码? - Erik Aronesty
不支持IE。但是IE在2022年6月14日已经停止更新。我认为这里的“现代”一词意味着前瞻性思维。 - undefined

42

如果您知道要保留和省略的属性列表,则以下“白名单”方法应有效:

const exampleFilter = ({ keepMe, keepMeToo }) => ({ keepMe, keepMeToo })

console.log(
  exampleFilter({
    keepMe: 'keepMe',
    keepMeToo: 'keepMeToo',
    omitMe: 'omitMe',
    omitMeToo: 'omitMeToo'
  })
)


这让我大开眼界,你能解释一下它是如何工作的吗? - rorymorris89
它使用参数解构和默认对象值的组合(每个键都映射到同名变量持有的值,例如{ keepMe,keepMeToo }就像{ keepMe: keepMe,keepMeToo: keepMeToo })。 - gyre
1
谢谢!非常棒的答案,已点赞。 - rorymorris89
哇!谢谢你!我一直在苦苦寻找答案,然后这个出现了!这个完美地解决了我的问题。 - J.H
1
很棒的答案!不知道是否有避免重复字段名称的方法,找不到任何信息。 - Camilo

27

在npm上有一个名为 blacklist 的包,其API非常灵活。

此外,还有一种情景技巧,使用了对象的剩余-扩展提案(阶段3)。

const {a, b, ...rest} = {a: 1, b: 2, c: 3, d: 4};
a // 1
b // 2
rest // {c: 3, d: 4}

这在React组件中经常使用,当您想使用一些属性并将其余部分作为props传递给<div {...props} />或类似组件时。


20

还有一种未被提及的解决方案:

省略单个

o = {a: 5, b: 6, c: 7}
Object.fromEntries(Object.entries(o).filter(e => e[0] != 'b'))
// Object { a: 5, c: 7 }
省略多个
o = {a: 1, b: 2, c: 3, d: 4}
exclude = new Set(['a', 'b'])
Object.fromEntries(Object.entries(o).filter(e => !exclude.has(e[0])))
// Object { c: 3, d: 4 }

使用上面的Set是因为它导致线性对数复杂度,即使exclude中的元素数量与o中的元素数量处于相同的渐近等价类。


3
帮助您在代码中省略一个字段而不留下未使用变量的解决方案。 - MadaShindeInai
很棒的回答。我将这些转化为函数并将其作为单独的答案发布在https://dev59.com/LVgQ5IYBdhLWcg3wSh91#76985658上。 - Jeremy Bernier

12

使用ES7和递归来省略一个键数组。

function omit(keys, obj) {
  if (!keys.length) return obj
  const { [keys.pop()]: omitted, ...rest } = obj;
  return omit(keys, rest);
}

这基于 @Eddie Cooro 的回答。


5
非递归版本:function omit(keys, obj) { return keys.reduce((a, e) => { const { [e]: omit, ...rest } = a; return rest; }, obj); }该函数用于删除JavaScript对象中指定的属性,其输入为一个由属性名组成的数组和一个对象。返回结果为包含其他所有属性但不包括指定属性的新对象。 - Magical Gordon
2
TypeScript非递归版本:export function omitObjectKeys<T extends object = {}>( keys: string[], obj: T, ): Partial<T> { return (keys as any).reduce((a: Partial<T>, e: keyof T) => { const { [e]: omitted, ...rest } = a; return rest; }, obj); } - Bogdan Surai
这是不必要的低效(具有实际影响),因为它会为每个需要省略的键复制整个对象。 - Ry-

7
你可以使用Object.assign(),delete。
var not = ["a", "b"]; // properties to delete from obj object
var o = Object.assign({}, obj);
for (let n of not) delete o[n];

或者

var props = ["c", "d"];
let o = Object.assign({}, ...props.map(prop => ({[prop]:obj[prop]})));

6
如果您已经使用过lodash,您也可以使用omit(obj, ["properties", "to", "omit"])来获取一个新的对象,其中不包含在数组中提供的属性。

6

在其他回答的基础上,如果没有需要重复使用或抽象化的必要,这将使用IIFE内联移除黑名单属性。

(
  ({
    // Properties to remove from `someObject`.
    omitMe,
    omitMeToo,
    // The rest of `someObject`, to keep.
    ...keep
  }) => keep
)(someObject)

例子

const someObject = {
  keepMe: 'keepMe',
  keepMeToo: 'keepMeToo',
  omitMe: 'omitMe',
  omitMeToo: 'omitMeToo',
};

console.log(
  (
    ({
      omitMe,
      omitMeToo,
      ...keep
    }) => keep
  )(someObject)
);


6
当然可以,为什么不用这样的东西呢:
var original = {
  name: 'Rory',
  state: 'Bored',
  age: '27'
};

var copied = Object.assign({}, original);
delete copied.age;

console.log(copied);

https://jsfiddle.net/4nL08zk4/


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