我听说过...
将它们称为“扩展语法”和“扩展运算符”,后者更受欢迎。相关MDN 文档的 URL表明它最初被称为扩展运算符,但后来更改为扩展语法,并且MDN 的运算符列表没有提及它。
谷歌似乎暗示运营商这个词更受欢迎和被接受,微软文档和es6-features.org等网站都这样引用它。
如果有的话,哪个术语在 ECMAScript 的上下文中是最正确的,为什么?数组解构赋值呢?
我听说过...
将它们称为“扩展语法”和“扩展运算符”,后者更受欢迎。相关MDN 文档的 URL表明它最初被称为扩展运算符,但后来更改为扩展语法,并且MDN 的运算符列表没有提及它。
谷歌似乎暗示运营商这个词更受欢迎和被接受,微软文档和es6-features.org等网站都这样引用它。
如果有的话,哪个术语在 ECMAScript 的上下文中是最正确的,为什么?数组解构赋值呢?
在这个词的所有意义上,它不是一个。自推出以来,它一直是一个巨大的误解,尽管有普遍的看法 - 它不是一个,并且有一些客观的观点需要说明:
应该提到的是,扩展语法有不同的“风格”,在不同的上下文中使用,并且在使用相同的标点符号时通常用不同的名称来引用。...
传播语法基本上是标点符号应用的总称,请参阅Felix Kling的精彩回答,详细说明所有用途和名称。补充答案中给出了有关这些个人用途的更多说明。
从语义上讲,在 ECMAScript 的上下文中,运算符只是接受参数并计算为单个值的内置函数——用前缀、中缀或后缀表示法编写,通常使用符号名称,例如+
or /
。来自维基百科:
简单地说,涉及运算符的表达式以某种方式进行评估,结果值可能只是一个值(一个 r 值),或者可能是一个允许赋值的对象(一个 l 值)。
例如,+
运算符产生一个值,例如 2,它是一个右侧表达式,并且该.
运算符产生一个允许赋值的对象,例如foo.bar
,一个左侧表达式。
从表面上看,...
标点符号1看起来是一个前缀一元运算符:
const baz = [foo, ...bar];
但是该论点的问题在于...bar
它不能评估为奇异值。它一个一个地传播 iterablebar
的元素。传播参数也是如此:
foo(...bar);
在这里,从 iterablefoo
接收单独bar
的参数。它们是传递给 的单独值foo
,而不仅仅是一个值。它不符合运算符的定义,所以它不是一个。
需要说明的另一点是,运算符应该是独立的并返回单个值。例如:
const bar = [...foo];
如前所述,这很好用。当您尝试执行此操作时会出现问题:
const bar = ...foo;
如果扩展语法是运算符,则后者可以正常工作,因为运算符将表达式评估为单个值,但扩展不是,因此它失败了。扩展语法和扩展参数仅适用于数组和函数调用的上下文,因为这些结构接收由扩展数组元素或参数提供的多个值。评估多个值超出了操作员的能力范围。
完整的运算符列表在ECMAScript 2015 语言规范的第 12.5 到 12.15 条中列出,该规范中...
引入了...
. 也可以推断它不是算子。这个答案中提到的两种主要情况,其中传播语法在生产中,用于函数调用(传播参数)或数组文字(传播语法)如下所述:
数组字面量: [省略选择] [元素列表] [ 元素列表 , Elisionopt ] 元素列表: 省略选择赋值表达式省略选择 SpreadElement ElementList , 省略选择AssignmentExpression ElementList , 省略选择SpreadElement 省略: , 省略, 传播元素: ... 赋值表达式
对于函数调用:
调用表达式: 成员表达式参数 论据: ( ) (参数列表) 参数列表: 赋值表达式 ... 赋值表达式 参数列表,赋值表达式 ArgumentList , ... 赋值表达式
在这些作品中,可以得出一个结论:传播“算子”不存在。如前所述,运算符应该是独立的,例如const bar = ...foo
并计算为单个值。语言的语法阻止了这种情况,这意味着传播语法从来都不是独立的。它是对数组初始值设定项和函数调用的扩展,是对它们语法的扩展。
语法,由Wikipedia定义:
在计算机科学中,计算机语言的语法是定义符号组合的一组规则,这些符号组合被认为是该语言中结构正确的文档或片段。
语法基本上是语言的“形式”,是关于代码外观和代码应该如何编写合法或不合法的规则。在这种情况下,ECMAScript 的语法专门将...
标点符号定义为仅出现在函数调用和数组文字中作为扩展——这是一个定义...foo
被认为是合法的符号 ( ) 组合在一起的规则,因此它的语法类似于箭头函数 ( =>
) 不是运算符,而是语法2。
打电话...
给接线员是用词不当。运算符是一个内置函数,它接受参数(操作数),采用前缀、中缀或后缀表示法的形式,并且只计算一个值。...
,虽然满足前两个条件,但不满足最后一个条件。...
相反,它是语法,因为它是在语言的语法中明确而明确地定义的。因此,“扩展运算符”在客观上更正确地称为“扩展语法”。
1术语“标点符号”是指ECMAScript 2015及更高版本规范中的标点符号。这些符号包括语法组件和运算符,并且是语言的标点符号。...
本身就是一个标点符号,但术语“扩展语法”指的是标点符号的整个应用。
2 =>
本身就是一个标点符号,正如...
我所指的具体是箭头函数语法,=>
标点符号((…) => { … }
)的应用,正如扩展语法是指...
标点符号的应用。
主要答案中未涵盖传播/休息语法的其他众多用途。他们包括:
扩展语法的用法,通常称为rest语法,用于函数参数中可变数量的参数。这与散布参数不同,散布参数用于将参数传递给基于可迭代元素的函数调用。例如:
function add(...addends) {
…
}
在这里,rest 语法用于函数add
接收标识符中的其余addends
参数。这似乎确实评估为奇异值,就像addends
传递的参数数组一样,但是如果我们尝试:
function foo(...[bar, baz]) {
…
}
在这里,bar
并且baz
都将被分配一个与传递的第一个和第二个参数相对应的值——因此这并不总是评估为一个值。潜在的问题是,...addends
在第一个示例和...[bar, baz]
第二个示例中,实际上根本没有计算出一个值——它只是在将参数数组分配给标识符的操作期间使用。因此,它的语法允许函数的参数数量可变,而不是运算符。
扩展语法也可以在数组解构赋值期间使用,实际上在语言规范中被称为剩余元素(因为在解构中使用时,它会获取剩余的解构迭代)。可以提出一个令人信服的论点,因为这看起来确实像一个运算符:
const [...bar] = [1, 2, 3];
它像前缀一元运算符一样使用。在这里,bar
计算为[1, 2, 3]
- 这是一个单一的值。但这并不总是发生,例如:
const [first, ...[second, third]] = [1, 2, 3];
在这里,first
、second
和third
分别计算为 1、2 和 3。但是...[second, third]
分配给两个标识符,而不是一个,并且不会评估为奇异值,而是两个。就像 rest 语法一样,潜在的问题是...bar
在第一个示例和...[second, third]
第二个示例中实际上根本没有计算出一个值——它只是在赋值操作期间使用。因此,它根本不是运算符2,只是帮助解包值的新语法。
扩展语法的最终用途是对象文字,通常称为“对象扩展属性”,其中目标对象自己的可枚举属性被传播到另一个对象,例如:
const foo = { ...bar };
这不是运算符,就像数组扩展语法不是运算符一样。这个概念是一样的,而不是数组中的索引和元素,bar
的可枚举键和值被传播到foo
. 在这里,一组的bar
属性被传播——不仅仅是一个单一的值,因此它不符合运算符的定义。
1 Object rest/spread 属性目前处于 ECMAScript 的第 3 阶段提案中,并且很可能会在不久的将来添加
2除了语义之外,解构赋值作为运算符的另一个问题是语言规范将其定义为补充语法——而不是补充运算符,这是理所当然的。它不是独立的,因为这不起作用:
const ...bar = [1, 2, 3, 4];
它是上下文相关的,只有语言的语法、对象字面量和左侧表达式的数组字面量才允许。它也是改进左侧表达式解释的语法。同样,这是向语言添加新语法的扩展,是对现有语法的改进。这重申了规范的论点。