【问题标题】:How to destructure into dynamically named variables in ES6?如何在 ES6 中解构为动态命名的变量?
【发布时间】:2016-06-26 15:26:22
【问题描述】:

假设我有以下对象:

const user = { 
  id: 42, 
  displayName: "jdoe",
  fullName: { 
      firstName: "John",
      lastName: "Doe"
  }
};

我只想要idfullName

我会做以下事情:

const { id, fullName } = user

很简单,对吧?

现在假设我想根据另一个名为 fields 的变量的值进行解构。

const fields = [ 'id', 'fullName' ]

现在我的问题是:如何根据键数组进行解构?

我无耻地尝试了以下方法但没有成功:

let {[{...fields}]} = userlet {[...fields]} = user。有什么办法可以做到吗?

谢谢

【问题讨论】:

  • 这是一个关于解构所有属性的相关问题:stackoverflow.com/questions/31907970/… - 可能同样的答案也适用于这里
  • 如果将fields 更改为空数组,那么您将不会创建任何变量,并且之后的任何代码都会受到威胁。使用带有文字的 const 可以确保可以事先确定风险,但像 fields = nonliteralvar 这样的东西会产生问题。

标签: javascript ecmascript-6


【解决方案1】:

Paul Kögel 的回答很好,但我想举一个更简单的例子来说明当您只需要动态字段的值但不需要将其分配给动态键时。

let obj = {x: 3, y: 6};
let dynamicField = 'x';

let {[dynamicField]: value} = obj;

console.log(value);

【讨论】:

    【解决方案2】:

    你不能在不知道键名或为命名变量使用别名的情况下进行破坏

    // you know the name of the keys
    const { id, fullName } = user;
    
    // use an alias for named variables
    const { [fields[0]]: id, [fields[1]]: fullName } = user; 
    

    一种解决方案是使用Array.reduce() 创建一个带有动态键的对象,如下所示:

    const user = { 
      id: 42, 
      displayName: "jdoe",
      fullName: { 
          firstName: "John",
          lastName: "Doe"
      }
    };
    
    const fields = [ 'id', 'fullName', 'age' ];
    
    const obj = fields.reduce((acc, k) => ({ ...acc, ...(user.hasOwnProperty(k) && { [k]: user[k] }) }), {});
    
    for(let k in obj) {
      console.log(k, obj[k]);
    }

    【讨论】:

      【解决方案3】:

      如前所述,如果不使用 eval,您将无法在 JavaScript 中将其析构为动态命名的变量。

      但是你可以动态获取对象的一个​​子集,使用reduce函数如下:

      const destruct = (obj, ...keys) => 
        keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
      
      const object = { 
        color: 'red',
        size: 'big',
        amount: 10,
      };
      
      const subset1 = destruct(object, 'color');
      const subset2 = destruct(object, 'color', 'amount', 'size');
      console.log(subset1);
      console.log(subset2);

      【讨论】:

      【解决方案4】:

      使用动态密钥进行解构并非不可能。为了防止创建动态变量的问题(如 Ginden 所述),您需要提供别名。

      const user = { 
        id: 42, 
        displayName: "jdoe",
        fullName: { 
            firstName: "John",
            lastName: "Doe"
        }
      };
      
      const fields = [ 'id', 'fullName' ];
      const object = {};
      
      const {[fields[0]]: id, [fields[1]]: fullName} = user;
      
      console.log(id); // 42
      console.log(fullName); // { firstName: "John", lastName: "Doe" }
      

      要解决必须为动态值定义静态别名的问题,您可以分配给对象的动态属性。在这个简单的例子中,这与恢复整个解构是一样的,虽然:)

      const user = { 
        id: 42, 
        displayName: "jdoe",
        fullName: { 
            firstName: "John",
            lastName: "Doe"
        }
      };
      
      const fields = [ 'id', 'fullName' ];
      const object = {};
      
      ({[fields[0]]: object[fields[0]], [fields[1]]: object[fields[1]]} = user);
      
      console.log(object.id); // 42
      console.log(object.fullName); // { firstName: "John", lastName: "Doe" }
      

      来源:

      【讨论】:

      • 不幸的是,您提出的解决方案都没有按要求回答问题。
      【解决方案5】:

      简答:不可能,也不可能。

      这背后的原因:它会将新的动态命名变量引入块作用域,实际上是动态的eval,从而禁用任何性能优化。可以动态修改作用域的动态eval 一直被认为是极其危险的,因此已从 ES5 严格模式中删除。

      此外,这将是一种代码异味 - 引用未定义的变量会抛出 ReferenceError,因此您需要更多样板代码来安全地处理这种动态范围。

      【讨论】:

      • 这确实是一种代码味道。最终使用了另一种方法。
      • 您提出的范围界定点是无懈可击的。然而,至少有一种情况本身不是代码异味。即,当您有一个函数接受一个或多个要在迭代中使用的键时。 omitpluckreduce 的特殊版本都是动态解构有助于提高可读性的情况。在对象中动态分配字段名称既是可能的,也是启用 DRYer 代码(即更多代码共享)的绝佳方式。同样,指针的动态分配可以帮助 DRY 代码,而无需使用 hashmap 来规避语言限制。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 2021-10-01
      相关资源
      最近更新 更多