程序化解构

时间:2018-07-18 10:31:05

标签: javascript

我有一个不同的用例,其中在使用解构概念时,我希望新变量的名称来自不同的变量。

对于前(通常为解构):

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo, bar); // Works fine

工作正常,但是当我尝试用其他变量替换p, foo, q, bar时出现错误,因为语法不正确。

最接近的是:

var o = {p: 42, q: true};
var x1 = "p";
var x2 = "foo";
var x3 = "q";
var x4 = "bar";
var {[x1]: foo, [x3]: bar} = o;
console.log(foo, bar);

我尝试但没有奏效的事情是:

var {[x1]: window[x2], [x3]: bar} = o; //Uncaught SyntaxError: Unexpected token [
var {[x1]: (()=>x2)(), q: bar} = o; //Uncaught SyntaxError: Unexpected token (

但是在这里,我仍然无法将foo, bar替换为x2, x4

有人知道如何实现这一目标吗?还是有可能这样做?

2 个答案:

答案 0 :(得分:2)

您需要分配一个左值,但是据我所知,您不能像let [dynamicName] = value那样声明动态生成的变量名。但是,对象属性是一种替代方法,可以动态生成:

var o = {p: 42, q: true};
var container = {};
var x1 = "p";
var x2 = "foo";
var x3 = "q";
var x4 = "bar";
({[x1]: container[x2], [x3]: container[x4]} = o);
console.log(container.foo, container.bar);

在全局范围内,您可以滥用将全局对象用作对象环境这一事实,并使用window[x2]window[x4],但这在生产代码中并不是真正有用的。

答案 1 :(得分:1)

in this comment得到了很好的回答。我会尝试用规格说明来解释。

当我们声明一个变量时,就像这样

var {[x1]: window[x2], [x3]: window[x4]} = o;

为了简洁起见,我从规范中删除了所有下标文字

它将按照Variable Statement Section进行以下生产,

VariableStatement:
    var VariableDeclarationList;

VariableDeclarationList:
    VariableDeclaration
    VariableDeclarationList, VariableDeclaration

VariableDeclaration:
    BindingIdentifier Initializer
    BindingPattern Initializer

由于{[x1]: window[x2], [x3]: window[x4]}不是BindingIdentifier,所以它是BindingPattern。那生产就像这样

BindingPattern:
    ObjectBindingPattern
    ArrayBindingPattern

ObjectBindingPattern:
    {}
    {BindingRestProperty}
    {BindingPropertyList}
    {BindingPropertyList, BindingRestProperty}

...
...

BindingPropertyList:
    BindingProperty
    BindingPropertyList, BindingProperty

...
...

BindingProperty:
    SingleNameBinding
    PropertyName: BindingElement

BindingElement:
    SingleNameBinding
    BindingPattern Initializer

SingleNameBinding:
    BindingIdentifier Initializer

在这种情况下({[x1]: window[x2], [x3]: window[x4]},生产像这样BindingPattern-> ObjectBindingPattern-> {BindingPropertyList}-> BindingProperty-> {{1 }}-> PropertyName: BindingElement-> SingleNameBinding

在这一点上,BindingIdentifier不是window[x2]。这就是为什么您得到BindingIdentifierSyntaxError的原因。


但是它在Uncaught SyntaxError: Unexpected token [的情况下有效,因为它不再是变量声明。这是destructuring assignment

为此生产

({[x1]: window[x2], [x3]: window[x4]} = o)

此处的制作已完成,AssignmentPattern: ObjectAssignmentPattern ArrayAssignmentPattern ObjectAssignmentPattern: {} {AssignmentRestProperty} {AssignmentPropertyList} {AssignmentPropertyList, AssignmentRestProperty} AssignmentPropertyList: AssignmentProperty AssignmentPropertyList, AssignmentProperty AssignmentProperty: IdentifierReference Initializer PropertyName: AssignmentElement AssignmentElement: DestructuringAssignmentTarget Initializer DestructuringAssignmentTarget: LeftHandSideExpression LeftHandSideExpression: NewExpression CallExpression CallExpression: CoverCallExpressionAndAsyncArrowHead SuperCall CallExpression Arguments CallExpression[Expression] CallExpression.IdentifierName CallExpression TemplateLiteral 。这就是CallExpression[Expression]有效且有效的原因。