解构赋值:参数顺序相互依赖

Destructuring assignment: order of parameters that depend on each other

我以为解构是在检索到所有参数之后执行的,但是我注意到这段代码有效。

function extract(propertyName, { [propertyName]: value }) {
  console.log(propertyName, value);
}

extract('property', { property: 'value' });

虽然这个没有。

function extract({ [propertyName]: value }, propertyName) {
  console.log(propertyName, value);
}

extract({ property: 'value' }, 'property');

这推翻了我最初的想法,但我找不到任何文档或规范来解释确切的行为。

参数值是按顺序确定的,就像您将每个参数写成自己的let声明一样,从收到的实际参数中获取值。 (不是它的实际工作方式,这只是一个类比。)

所以你的第一个例子在概念上是这样的:

// ONLY CONCEPTUAL
function extract() {
    let propertyName = /*...the first actual argument...*/;
    let { [propertyName]: value } = /* ...the second actual argument... */;
    console.log(propertyName, value);
}

而你的第二个行为是这样的:

// ONLY CONCEPTUAL
function extract() {
    let { [propertyName]: value } = /* ...the first actual argument... */;
    let propertyName = /*...the second actual argument...*/;
    console.log(propertyName, value);
}

...所以它在“变量”初始化之前尝试使用 propertyName 的值,得到一个错误。 (因为参数表达式是在 ES2015 中添加的,所以它们使用 let 而不是 var 语义。)

另一种看待它的方式是,如果将整个参数列表视为迭代器解构的内容,它的工作方式完全相同。这样想,你的第一个例子是:

//  v−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−v−−−−− iterable destructuring
let [propertyName, { [propertyName]: value }] = /* an iterable for the actual arguments */;
//   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^−−−−−− parameter list

FunctionDeclarationInstantiation and IteratorBindingInitialization 部分的规范中对此进行了介绍。

请注意,这实际上与解构没有任何关系,只是当函数代码为 运行 时参数值如何分配给参数。例如,如果您尝试在较早参数的默认值表达式中使用较晚的参数名称,它会因同样的原因而失败。