【问题标题】:Omit property variable when using object destructuring使用对象解构时省略属性变量
【发布时间】:2019-10-02 17:37:59
【问题描述】:

这是一个例子:

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

const { a, ...rest } = initObject

我们从对象中省略了属性 a,但随后 const a 被分配了一个值,但从未使用过 - 来自 eslint 的错误 (no-unused-vars)。是否可以完全省略const a

【问题讨论】:

    标签: javascript ecmascript-6 eslint object-destructuring


    【解决方案1】:

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

    例如

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

    或者使用ignoreRestSiblings

    ignoreRestSiblings 选项是一个布尔值(默认值:false)。使用 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 documentation

    JavaScript delete 运算符从对象中删除属性

    例如

    const initObject = {
      a: 0,
      b: 0,
      c: 0
    }
    
    const rest = { ...initObject }; // create a shallow copy
    delete rest.a;
    
    console.log(rest);

    【讨论】:

    • 谢谢,但我不想禁用警告,我想以“正确的方式”:)
    • 好吧,我想我会忽略它。但我想知道,未使用的变量是如何影响应用性能的?
    • @AlexanderKim 有趣的问题。但不幸的是,我还没有回答未使用变量的性能。
    • 为什么你把const rest = initObject改成了const rest = { ...initObject }
    • @AlexanderKim 因为它们不同。如果你引用initObject而不是创建浅拷贝,delete rest.a也会修改initObject
    【解决方案2】:

    来自 eslint 的错误(no-unused-vars)。

    no-unused-vars rules 有两个配置选项可以帮助您的用例:

    • ignoreRestSiblings option 是一个布尔值,默认为false。启用后,其余属性的兄弟姐妹将被忽略。这正是您所需要的!
    • varsIgnorePattern option 为不检查使用情况的变量名称指定了一个正则表达式模式。这允许我们为common underscore identifier 设置一个例外,以使用{ "varsIgnorePattern": "^_" } 显式标记未使用的变量。

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

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

    是否可以完全省略const a

    完全避免引入任何标识符的坏技巧是使用

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

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

    【讨论】:

    • 我不知道这两个规则,但这确实是我在 cmets 中建议的第一件事(现在已删除)。投我一票
    • 顺便说一句,对于您的最后一个块,const { a: {} = {}, ...rest } = initObject 将允许 a 成为 undefined,但看起来更糟。
    【解决方案3】:

    这似乎与@R3tep's answer 略有偏差,但它避免了将声明中的所有变量标记为已使用的陷阱:

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

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


    关于问题

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

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

    1. 如果您只需要属性bc,请仅解构这些属性:

      const { b, c } = initObject
      

      如果你不需要a,甚至不要承认它的存在。

    2. 如果您的输入有很多您需要处理的特定属性,并且您不能假设initObject 已经具有它需要的确切布局,然后避免使用反射方法或语法的诱惑,如Object.entries()for...inobject spread and rest syntax 等。

      继续单独处理您需要的特定属性,并将您的逻辑分解为可分离的函数,如果需要,每个函数都处理可管理的属性子集。

      另一方面,如果您可以预先设置您的输入以具有您已经需要的确切布局(例如,您可以假设initObject 只有bc) ,然后随意使用反射——这正是它的用途。

    3. 如果以上两点都不适合你,但你仍然发现你真的希望initObject 有很多任意属性,还有一些你想忽略,那么您应该使用此答案开头的建议(或其他适合您的答案之一)。

      但是,如上所述,这是代码异味,表明您的逻辑需要对对象的布局更加宽松1,或者您的输入前提条件需要更改2.

    【讨论】:

    • 谢谢,如果我有很多地方没有使用过的变量,那么性能呢?
    • 但是,如果在评估了我刚才指出的内容之后,这仍然被认为是必要的,那么在性能方面它相当于声明一个未使用的指针,也就是说它可以忽略不计。无论如何,优化器可能会注意到它未使用并完全删除声明。
    • @AlexanderKim 性能成本实际上是在...rest 部分,它迭代initObject 的剩余属性并将它们复制到rest,这是它被认为是代码的部分原因-闻起来。
    • @AlexanderKim 性能成本是毫无价值的,除非它们 1) 成为一个问题,并且 2) 您已经分析以确定性能瓶颈的确切位置。优化 1 毫秒和 4 个字节并不能在 100% 的使用 JavaScript 的用例中为您提供帮助。
    • @Delioth 1ms 很多。在这里,我们谈论的是 1/100μs 或更少。你的观点更好。
    【解决方案4】:

    您可以创建一个 IIFE 并将对象传递给它。

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

    【讨论】:

    • eslint 可能还会抱怨这个。 (我的解决方案是忽略 eslint,但这只是我。)
    • @Pointy 也许使用逗号操作符会起作用。查看更新。
    【解决方案5】:

    技术上满足 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,允许重复标识符:

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

    但这有点奇怪。正如其他答案所建议的那样,我更喜欢配置/忽略 linter,或者使用解构以外的东西。

    【讨论】:

      【解决方案6】:

      您可以使用Object.assign() 创建对象的浅表副本,然后简单地删除该属性。

      const initObject = {
        a: 0,
        b: 0,
        c: 0
      }
      
      let rest = Object.assign({}, initObject);
      delete rest.a;
      
      console.log(rest);
      console.log(initObject);

      【讨论】:

        【解决方案7】:

        试试

        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 未使用。
        【解决方案8】:

        为了省略(清理) 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。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-06-15
          • 1970-01-01
          • 2016-12-10
          • 2018-04-15
          • 2011-11-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多