使用对象解构时省略属性变量

48

这里有一个例子:

const initObject = {
  a: 0,
  b: 0,
  c: 0
}

const { a, ...rest } = initObject

我们从对象中省略了属性a,但是然后给const a赋值,但是它从未被使用 - eslint的错误(no-unused-vars)。是否可能完全省略const a

8个回答

46

一种可能的方法是使用// eslint-disable-next-line no-unused-vars

例如:

// eslint-disable-next-line no-unused-vars
const { a, ...rest } = initObject

或者通过使用ignoreRestSiblings来实现。

ignoreRestSiblings选项是一个布尔值(默认为false)。使用Rest属性可以从对象中“省略”属性,但默认情况下兄弟属性被标记为“未使用”。启用此选项后,忽略了rest属性的兄弟属性。

例如:

/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
// 'a' is ignored because it has a rest property sibling.
const { a, ...rest } = initObject;

了解有关no-unused-vars的更多信息。


但是,如果您的目标是删除属性a,则还有另一种方法。
您可以使用delete运算符。

来自MDN文档

JavaScript的delete运算符从对象中移除一个属性

例如:

const initObject = {
  a: 0,
  b: 0,
  c: 0
}

const rest = { ...initObject }; // create a shallow copy
delete rest.a;

console.log(rest);


2
谢谢,但我不想禁用警告,我想要“正确的方法” :) - Alexander Kim
好吧,我想我只能忽略它了。但是我在想,未使用的变量会如何影响应用程序的性能? - Alexander Kim
@AlexanderKim 有趣的问题。但不幸的是,我对未使用变量的性能没有答案。 - R3tep
似乎“删除(delete)”是更好的选择。 - Alexander Kim
1
为什么你把 const rest = initObject 改成了 const rest = { ...initObject } - Alexander Kim
3
因为它们是不同的。如果您引用initObject而不是创建浅拷贝,delete rest.a也会修改initObject - Patrick Roberts

24

eslint出现错误 (no-unused-vars)

no-unused-vars规则有两个配置选项可帮助您解决此问题:

  • ignoreRestSiblings选项是一个布尔值,默认为false。启用时,将忽略rest属性的兄弟姐妹。这正是您需要的!
  • varsIgnorePattern选项指定变量名称的正则表达式模式,以不检查使用情况的变量名。这使我们可以针对常见的下划线标识符进行例外处理,以通过{ "varsIgnorePattern": "^_" }明确标记未使用的变量。

const { a:_, ...rest } = initObject;
//       ^^

不幸的是,您仍需要避免多次声明_变量,因此要省略多个属性,您需要执行类似于{ a:_a, b:_b, ...rest } = …的操作。

是否可以完全省略const a

一种完全避免引入任何标识符的不好办法是使用

const { a:{}, ...rest } = initObject;
//       ^^^

进一步将.a属性值解构为一个对象,但这需要确保该属性存在且不持有nullundefined值。


我不知道这两个规则,但这确实是我在评论中建议的第一件事(现在已被删除)。给你点赞。 - Patrick Roberts
1
顺便说一下,对于你的最后一个代码块,const { a: {} = {}, ...rest } = initObject 可以允许 aundefined,但看起来更糟糕。 - Patrick Roberts

9

这似乎是与@R3tep的答案微不足道的偏差,但这避免了将声明中的所有变量都标记为已使用的陷阱:

const initObject = {
  a: 0,
  b: 0,
  c: 0
}

const {
  a, // eslint-disable-line no-unused-vars
  ...rest
} = initObject

现在,如果未使用rest,它仍会导致eslint错误。


关于问题:

删除属性的正确方法是什么?

我将回答您应该提出的问题。处理具有不需要的属性的对象的正确方法是以一种隐式地忽略它们的方式重写您的逻辑。

  1. If you just need the properties b and c, destructure only those properties:

    const { b, c } = initObject
    

    Don't even acknowledge that a exists if you don't need it.

  2. If your input has a lot of specific properties you need to deal with, and you can't assume that initObject already has the exact layout it needs, then avoid the temptation to use reflection methods or syntax like Object.entries(), for...in, object spread and rest syntax, etc.

    Continue to handle the specific properties you need on an individual basis, and break up your logic into separable functions that each deal with a manageable subset of the properties, if necessary.

    On the other hand, if you can precondition your input to have the exact layout you already need (e.g. you are able to assume that initObject only has b and c), then feel free to use reflection -- that's exactly what it's for.

  3. If neither of the above two points applies to you and you still find that you really want initObject to have a lot of arbitrary properties, and a few that you want to ignore, then you should use the suggestion at the beginning of this answer (or one of the other answers that works for you).

    However, as noted, this is code-smell and an indicator that your logic needs to be more lenient with the layout of the object1, or your preconditions for the input need to change2.


谢谢,那性能方面呢?如果我有很多未使用的变量会怎样? - Alexander Kim
1
但是,如果在评估了我刚才指出的内容之后,仍然认为有必要这样做,那么从性能上来看,它与声明未使用的指针大致相当,也就是说,它是可以忽略不计的。无论如何,优化器可能会注意到它未被使用并完全删除该声明。 - Patrick Roberts
@AlexanderKim 实际上性能成本在于 ...rest 部分,它会迭代 initObject 的剩余属性并将它们复制到 rest 中,这也是为什么它被认为是代码异味的一部分。 - Patrick Roberts
@AlexanderKim 你可以使用delete操作符。 - R3tep
5
在性能成为问题,并且你已经通过分析确定了性能瓶颈之前,考虑性能成本是毫无意义的。优化1毫秒和4字节并不能在你使用JavaScript的100%使用情况下帮助你。 - Delioth
2
@Delioth,1毫秒是很长的时间。在这里,我们更多地谈论1/100微秒或更短的时间。你的观点更好。 - Kaiido

2
你可以创建一个IIFE并将对象传递给它。"最初的回答"。

const initObject = {
  a: 0,
  b: 0,
  c: 0
}
const res = (({a,...rest}) => (a,rest))(initObject);
console.log(res)


这有可能会让eslint仍然抱怨。 (我的解决方案是忽略eslint,但这只是针对我个人而言。) - Pointy
1
@Pointy 或许使用逗号运算符会起作用。请查看更新。 - Maheer Ali

2
一个技术上符合linter规则的选项是提前声明rest,将a属性解构为rest,然后使用rest语法将对象的其余部分放入rest变量名中。
最初的回答: 一种符合linter规则的技术选项是先声明“rest”,再把“a”属性解构到“rest”中,最后使用rest语法将对象的其余部分放入“rest”变量中。

const initObject = {
  a: 0,
  b: 0,
  c: 0
};
let rest;
({ a: rest, ...rest } = initObject);

console.log(rest);

很遗憾,如果你想避免使用var,你不能像这样在单行中完成。"最初的回答"
let { a: rest, ...rest } = initObject

因为当{的左侧声明一个变量时,右侧每个新的变量名称都会被单独初始化 - 对解释器来说,它看起来有点像"最初的回答"。
let rest = initObject.a;
let rest = <everything else in initObject>

但是,对于同一变量名的重复let标识符是不允许的。您可以使用var在一行中完成它,因为var允许重复标识符:

最初的回答

const initObject = {
  a: 0,
  b: 0,
  c: 0
};
var { a: rest, ...rest } = initObject;

console.log(rest);

但这有点奇怪。我更喜欢配置/忽略linter,或者像其他回答建议的那样使用其他技术。

最初的回答


1
尝试
const rest = ((o)=> (delete o.a,o))({...initObject});

'use strict'

const initObject = {
  a: 0,
  b: 0,
  c: 0
}

const rest = ((o)=> (delete o.a,o))({...initObject});

console.log({initObject,rest});


没有逗号运算符,我很确定 eslint 仍然会抱怨 a 没有使用。 - Patrick Roberts

1
你可以使用 Object.assign() 创建一个浅拷贝对象,然后简单地删除属性。

const initObject = {
  a: 0,
  b: 0,
  c: 0
}

let rest = Object.assign({}, initObject);
delete rest.a;

console.log(rest);
console.log(initObject);


-1

为了省略(清理)ID和密码属性,以下是最终在单个对象中运行的代码。

这是产品和用户模型之间关系的响应。

   return {...product,
        author: [
            `username: ` + product['author'].username,
            `email: ` + product['author'].email,
        ]};

否则,对于一个数组,我使用了:
    return products.map(product => [{ 
        'title' : product['title'],
        'description' : product['description'],
        'price' : product['price'],
        'updated' : product['updatedAt'],
        'author': {
            'username' : product['author'].username,
            'email' : product['author'].email,
        },                   
    }]);

我正在使用PostgreSQL、Nest、Objection和Knex。

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