JavaScript对象解构和别名化

20

在JavaScript中,是否有一种方式可以解构对象并为本地解构的对象创建别名?

类似于:

const env = {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;

...并且使env成为一个本地常量,其中包含了那些被选定的环境变量。(我知道我的示例在babel中无法工作)

{
  ENV_VAR_X: "s867c7dsj4lal7", 
  ENV_VAR_Y: "hd73m20s-a=snf77f", 
  ENV_VAR_Z: "production"
}

有没有办法实现这种别名?

另外一件事,我正在使用Babel作为我的转译器,然后在Node中运行脚本以便我可以利用更多的ECMAScript 6功能。


在我的 Firefox Nightly 上可以运行。https://gist.github.com/liam4/393863561cb20e1b90b0 - Nebula
这既令人惊叹,同时也有些不幸!不过使用Babel6却不行 :( 我想要一个针对它的例子。 - Seth
我不确定在babel修复之前,使用解构是否真的可行.. :( - Nebula
它似乎也不适用于最新的Node :( 看来我必须采取冗长的方法。 - Seth
1
我已经在Babel的问题跟踪器中添加了一个功能请求。希望它能够尽快修复。没有什么方法可以实现这一点,而不必实质上编写双重赋值,一个用于解构对象,一个用于别名对象? - Seth
显示剩余7条评论
2个回答

19
根据我对规范的阅读,这应该是可解析的,但它的含义并不是你所想象的。它将从右到左解析。
const env = ({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env);

生产在哪里

({ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env)

就像其他所有的赋值语句一样,被定义为返回 RHS,即 process.env

因此,您的代码等效于

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = process.env;

这很容易验证:

const foo = {a: 1, b: 2};
const bar = {a} = foo;

这会导致一个新的常量a被声明,并赋值为1,正如您所期望的那样。然而,bar的值不是"解构对象的别名",它应该是{a: 1};它与foo相同,即{a: 1, b: 2}bar === foo


您所尝试的内容在SO和ES讨论组中已经被讨论了很多次。底线是没有办法做到这一点。您能做的只有:

const {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z} = process.env;
const env = {ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};

"换句话说,无法从一个对象中“解构出一个对象”,或者“选择一个对象到另一个对象”。你只能将一个对象解构为变量。"
"您可以回归到老式的方式:"
const env = {ENV_VAR_X: process.env.ENV_VAR_X, ...

我知道这很糟糕。

您可以使用underscore的pick函数或者编写自己的函数,但这需要您明确说明。

const env = _.pick(process.env, 'ENV_VAR_X', "ENV_VAR_Y', 'ENV_VAR_Z');

这里只是稍微好一点而已。

我们在ES7中提出了"剩余属性和展开属性", 但它们似乎并没有帮助我们解决这个问题。


我们需要的是一种新的语法,用于将属性选取到另一个对象中。已经提出了各种各样的建议,但没有一项得到了很大的关注。其中之一是“扩展点表示法”,它允许在点号后面放置一个花括号结构。在您的情况下,您将编写
const env = process.env.{ENV_VAR_X, ENV_VAR_Y, ENV_VAR_Z};
                       ^^

您可以在这里了解更多关于这个提案的信息。

明白了,这完全不可能吗?我的唯一选择是要么处理整个对象被分配给本地变量bar,要么定义一个包含目标对象所需属性的新变量? - Seth
“导致声明一个新的常量a,其值为1”,--- a不会被声明,因为该语句中没有对它进行声明。 - zerkms
“因此,你的代码等同于[...]”处存在严重错误:ENV_VAR_*变量变成了全局变量,而不是const。证明:(function() { const a = {x} = {x: 1}; })(); console.log(window.a === undefined && window.x === 1); // true - wchargin

8
要给一个已销毁的值分配一个新名称,只需使用以下代码:
obj = {x: 10, y: "Something"};
const { x: otherName } = obj;

虽然这是正确的,但这不是问题所在。你引用的已经在这里问/回答 - https://dev59.com/U1MI5IYBdhLWcg3wHHgz#57065418。我的情况是想知道语言中是否有从一个对象中选择属性到新对象的功能。 - Seth
要将一个对象的所有属性复制到另一个对象中,请使用 let newObject = {...fromObject}; 或者简单地使用 var clone = Object.assign({}, obj); 或者一种老式的方法 var clone = JSON.parse(JSON.stringify(obj)) - Amir Mehrnam
这是克隆一个对象的操作 :). 问题在于从一个对象中选择特定属性到一个新对象,这需要原生的两步过程。 - Seth
好的,我没有理解你的问题,但如果你正在使用TypeScript,那么我认为Pick实用类型就是你的答案。 - Amir Mehrnam
那种实用类型有助于表达我想要的对象的形状,但不能在运行时选择将值传递给该对象的实际操作。我必须利用接受的答案中提到的方法来实现运行时功能。 - Seth

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