是点差 "syntax" 还是点差 "operator"?
Is it spread "syntax" or the spread "operator"?
我听说 ...
被称为 'spread syntax' 和 'the spread operator',后者更受欢迎。相关MDN documentation suggests that it was initially referred to as the spread operator but later changed to spread syntax, and MDN's list of operators的URL没有提到。
Google 似乎表明术语 operator 更受欢迎和被接受,Microsoft documentation and es6-features.org 等网站就是这样引用它的。
哪个术语在 ECMAScript 的上下文中是最正确的,如果有的话,为什么?数组解构赋值呢?
它不是运算符。
在所有意义上,它都不是一个。自从它被引入以来,它一直是一个巨大的误解,尽管有流行的观点——它不是一个,有几点 objective 需要指出:
- 不符合运算符的定义
- 不能作为运算符使用
- 语言规范暗示它不是运算符
应该提到的是,扩展语法有不同的 'flavors',用于不同的上下文,并且通常在使用相同的标点符号时用不同的名称来指代。 Spread语法基本上是...
标点符号应用的总称,见's great answer detailing all the uses and names. More explanation about these individuals uses is given in .
什么是运算符?
从语义上讲,在 ECMAScript 的上下文中,运算符只是内置函数,它们接受参数并求值为 单个值 -- 以前缀、中缀或后缀表示法编写,并且通常带有符号名称,例如 +
或 /
。来自 Wikipedia:
Simply, an expression involving an operator is evaluated in some way, and the resulting value may be just a value (an r-value), or may be an object allowing assignment (an l-value).
例如,+
运算符产生一个值,例如 2,这是一个右侧表达式,.
运算符产生一个允许赋值的对象,例如 foo.bar
,左边的表达式。
从表面上看,...
标点符号1 看起来是一个前缀一元运算符:
const baz = [foo, ...bar];
但是该参数的问题在于 ...bar
的计算结果不是奇异值;它一个一个地传播可迭代的 bar
的元素。传播参数也是如此:
foo(...bar);
这里,foo
从可迭代的 bar
中接收 单独的 个参数。它们是传递给 foo
的独立值,而不仅仅是一个值。它不符合运算符的定义,所以不是运算符。
为什么不是运算符?
另一点是运算符是独立的,return 是一个单一的值。例如:
const bar = [...foo];
如前所述,这很有效。当您尝试这样做时出现问题:
const bar = ...foo;
如果传播语法是一个运算符,后者可以正常工作因为运算符将表达式计算为单个值但传播不会,所以它会失败。传播语法和传播参数仅适用于数组和函数调用的上下文,因为这些结构接收由传播数组元素或参数提供的多个值。评估多个值超出了操作员的能力范围。
标准怎么说?
运算符的完整列表列在 ECMAScript 2015 Language Specification, the specification in which ...
is introduced, which doesn't mention ...
. It can also be inferred that it's not an operator. The two main cases mentioned in this answer in which spread syntax is in a production, for function calls (spread arguments) or array literals(扩展语法)的第 12.5 至 12.15 条中,描述如下:
ArrayLiteral :
[ Elisionopt ]
[ ElementList ]
[ ElementList , Elisionopt ]
ElementList :
Elisionopt AssignmentExpression
Elisionopt SpreadElement
ElementList , Elisionopt AssignmentExpression
ElementList , Elisionopt SpreadElement
Elision :
,
Elision ,
SpreadElement :
... AssignmentExpression
CallExpression :
MemberExpression Arguments
Arguments :
( )
( ArgumentList )
ArgumentList :
AssignmentExpression
... AssignmentExpression
ArgumentList , AssignmentExpression
ArgumentList , ... AssignmentExpression
在这些作品中,可以得出一个结论:传播 'operator' 不存在。如前所述,运算符应该是独立的,如 const bar = ...foo
并计算为一个值。该语言的语法阻止了这种情况,这意味着传播语法从来就不是独立的。它是数组初始值设定项和函数调用的扩展,是它们语法的扩展。
为什么要传播'syntax'?
语法,由Wikipedia定义:
In computer science, the syntax of a computer language is the set of rules that defines the combinations of symbols that are considered to be a correctly structured document or fragment in that language.
语法基本上是语言的 'form',关于代码的外观以及代码的编写方式,管理合法与否的规则。在这种情况下,ECMAScript 的语法专门将 ...
标点符号定义为仅作为扩展出现在函数调用和数组文字中——这是定义符号组合 (...foo
) 的规则,这些符号被认为是在一起是合法的,因此它 syntax 类似于箭头函数 (=>
) 不是运算符,而是 syntax2。
调用 ...
操作员是用词不当。运算符是一种内置函数,它接受参数(操作数),采用前缀、中缀或后缀表示法 的形式,计算结果恰好为一个值 。 ...
,同时满足前两个条件,不满足最后一个。 ...
相反,是句法,因为它在语言的语法中明确明确地定义。因此,'the spread operator' objective更正确地称为 'spread syntax'。
1 术语'punctuator'指的是punctuators in ECMAScript 2015及以后的规范。这些符号包括句法成分和运算符,是语言的标点符号。 ...
本身是一个标点符号,但是 'spread syntax' 一词指的是标点符号的整个应用。
2 =>
本身就是一个 标点符号 ,就像 ...
但我指的是什么具体是箭头函数语法,=>
标点符号((…) => { … }
)的应用,正如扩展语法所指...
标点符号的应用。
语法的其他用途
spread/rest 语法的其他许多用途未包含在主要答案中。它们包括:
- 函数参数中的剩余语法
- 数组和对象1解构赋值
- 对象字面量中的对象扩展语法1
休息语法
扩展语法的用途,通常称为 rest 语法,用于函数的 arguments 中可变数量的参数.这与传播参数不同,传播参数用于将参数传递给基于可迭代元素的函数 call。例如:
function add(...addends) {
…
}
这里,rest语法用于函数add
接收标识符addends
中参数的rest。这似乎评估为奇异值,因为 addends
是传递参数的数组,但如果我们尝试:
function foo(...[bar, baz]) {
…
}
这里,bar
和 baz
都将被分配一个对应于传递的第一个和第二个参数的值——因此这并不总是计算为一个值。潜在的问题是第一个示例中的 ...addends
和第二个示例中的 ...[bar, baz]
实际上根本没有求值 - 它只是在将参数数组分配给标识符的操作期间使用.因此,它的语法允许函数的参数数量可变,而不是运算符。
解构赋值
扩展语法也可以在 array destructuring assignment 期间使用,实际上在语言规范中被称为 rest 元素(因为在解构中使用时,它得到 rest 的解构迭代)。可以提出一个令人信服的论据,因为这看起来确实像一个运算符:
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,只是帮助解包值的新语法。
对象传播语法
扩展语法的最终用途是对象字面量,通常称为 'object spread properties',其中目标对象自己的可枚举属性被扩展到另一个对象,例如:
const foo = { ...bar };
这不是运算符,就像数组展开语法不是运算符一样。概念是相同的,而不是数组中的索引和元素,bar
的可枚举键和值被扩展到 foo
。在这里,bar
属性的 集合 被传播——不仅仅是一个单一的值,因此它不符合运算符的定义。
1 Object rest/spread properties 目前处于 ECMAScript 的第 3 阶段提案中,很可能会在不久的将来添加
2 除了语义之外,解构赋值作为运算符的另一个问题是 the language specification 将其定义为 补充语法 -- 不是补充运算符,这是理所当然的。它不是独立的,因为这行不通:
const ...bar = [1, 2, 3, 4];
它是上下文相关的,只允许在语言的语法、左侧表达式的对象文字和数组文字中使用。它也是 改进左侧表达式 解释的语法。同样,这是向语言添加新 syntax 的扩展,是对现有语法的改进。这重申了规范的论点。
我听说 ...
被称为 'spread syntax' 和 'the spread operator',后者更受欢迎。相关MDN documentation suggests that it was initially referred to as the spread operator but later changed to spread syntax, and MDN's list of operators的URL没有提到。
Google 似乎表明术语 operator 更受欢迎和被接受,Microsoft documentation and es6-features.org 等网站就是这样引用它的。
哪个术语在 ECMAScript 的上下文中是最正确的,如果有的话,为什么?数组解构赋值呢?
它不是运算符。
在所有意义上,它都不是一个。自从它被引入以来,它一直是一个巨大的误解,尽管有流行的观点——它不是一个,有几点 objective 需要指出:
- 不符合运算符的定义
- 不能作为运算符使用
- 语言规范暗示它不是运算符
应该提到的是,扩展语法有不同的 'flavors',用于不同的上下文,并且通常在使用相同的标点符号时用不同的名称来指代。 Spread语法基本上是...
标点符号应用的总称,见
什么是运算符?
从语义上讲,在 ECMAScript 的上下文中,运算符只是内置函数,它们接受参数并求值为 单个值 -- 以前缀、中缀或后缀表示法编写,并且通常带有符号名称,例如 +
或 /
。来自 Wikipedia:
Simply, an expression involving an operator is evaluated in some way, and the resulting value may be just a value (an r-value), or may be an object allowing assignment (an l-value).
例如,+
运算符产生一个值,例如 2,这是一个右侧表达式,.
运算符产生一个允许赋值的对象,例如 foo.bar
,左边的表达式。
从表面上看,...
标点符号1 看起来是一个前缀一元运算符:
const baz = [foo, ...bar];
但是该参数的问题在于 ...bar
的计算结果不是奇异值;它一个一个地传播可迭代的 bar
的元素。传播参数也是如此:
foo(...bar);
这里,foo
从可迭代的 bar
中接收 单独的 个参数。它们是传递给 foo
的独立值,而不仅仅是一个值。它不符合运算符的定义,所以不是运算符。
为什么不是运算符?
另一点是运算符是独立的,return 是一个单一的值。例如:
const bar = [...foo];
如前所述,这很有效。当您尝试这样做时出现问题:
const bar = ...foo;
如果传播语法是一个运算符,后者可以正常工作因为运算符将表达式计算为单个值但传播不会,所以它会失败。传播语法和传播参数仅适用于数组和函数调用的上下文,因为这些结构接收由传播数组元素或参数提供的多个值。评估多个值超出了操作员的能力范围。
标准怎么说?
运算符的完整列表列在 ECMAScript 2015 Language Specification, the specification in which ...
is introduced, which doesn't mention ...
. It can also be inferred that it's not an operator. The two main cases mentioned in this answer in which spread syntax is in a production, for function calls (spread arguments) or array literals(扩展语法)的第 12.5 至 12.15 条中,描述如下:
ArrayLiteral : [ Elisionopt ] [ ElementList ] [ ElementList , Elisionopt ] ElementList : Elisionopt AssignmentExpression Elisionopt SpreadElement ElementList , Elisionopt AssignmentExpression ElementList , Elisionopt SpreadElement Elision : , Elision , SpreadElement : ... AssignmentExpression
CallExpression : MemberExpression Arguments Arguments : ( ) ( ArgumentList ) ArgumentList : AssignmentExpression ... AssignmentExpression ArgumentList , AssignmentExpression ArgumentList , ... AssignmentExpression
在这些作品中,可以得出一个结论:传播 'operator' 不存在。如前所述,运算符应该是独立的,如 const bar = ...foo
并计算为一个值。该语言的语法阻止了这种情况,这意味着传播语法从来就不是独立的。它是数组初始值设定项和函数调用的扩展,是它们语法的扩展。
为什么要传播'syntax'?
语法,由Wikipedia定义:
In computer science, the syntax of a computer language is the set of rules that defines the combinations of symbols that are considered to be a correctly structured document or fragment in that language.
语法基本上是语言的 'form',关于代码的外观以及代码的编写方式,管理合法与否的规则。在这种情况下,ECMAScript 的语法专门将 ...
标点符号定义为仅作为扩展出现在函数调用和数组文字中——这是定义符号组合 (...foo
) 的规则,这些符号被认为是在一起是合法的,因此它 syntax 类似于箭头函数 (=>
) 不是运算符,而是 syntax2。
调用 ...
操作员是用词不当。运算符是一种内置函数,它接受参数(操作数),采用前缀、中缀或后缀表示法 的形式,计算结果恰好为一个值 。 ...
,同时满足前两个条件,不满足最后一个。 ...
相反,是句法,因为它在语言的语法中明确明确地定义。因此,'the spread operator' objective更正确地称为 'spread syntax'。
1 术语'punctuator'指的是punctuators in ECMAScript 2015及以后的规范。这些符号包括句法成分和运算符,是语言的标点符号。 ...
本身是一个标点符号,但是 'spread syntax' 一词指的是标点符号的整个应用。
2 =>
本身就是一个 标点符号 ,就像 ...
但我指的是什么具体是箭头函数语法,=>
标点符号((…) => { … }
)的应用,正如扩展语法所指...
标点符号的应用。
语法的其他用途
spread/rest 语法的其他许多用途未包含在主要答案中。它们包括:
- 函数参数中的剩余语法
- 数组和对象1解构赋值
- 对象字面量中的对象扩展语法1
休息语法
扩展语法的用途,通常称为 rest 语法,用于函数的 arguments 中可变数量的参数.这与传播参数不同,传播参数用于将参数传递给基于可迭代元素的函数 call。例如:
function add(...addends) {
…
}
这里,rest语法用于函数add
接收标识符addends
中参数的rest。这似乎评估为奇异值,因为 addends
是传递参数的数组,但如果我们尝试:
function foo(...[bar, baz]) {
…
}
这里,bar
和 baz
都将被分配一个对应于传递的第一个和第二个参数的值——因此这并不总是计算为一个值。潜在的问题是第一个示例中的 ...addends
和第二个示例中的 ...[bar, baz]
实际上根本没有求值 - 它只是在将参数数组分配给标识符的操作期间使用.因此,它的语法允许函数的参数数量可变,而不是运算符。
解构赋值
扩展语法也可以在 array destructuring assignment 期间使用,实际上在语言规范中被称为 rest 元素(因为在解构中使用时,它得到 rest 的解构迭代)。可以提出一个令人信服的论据,因为这看起来确实像一个运算符:
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,只是帮助解包值的新语法。
对象传播语法
扩展语法的最终用途是对象字面量,通常称为 'object spread properties',其中目标对象自己的可枚举属性被扩展到另一个对象,例如:
const foo = { ...bar };
这不是运算符,就像数组展开语法不是运算符一样。概念是相同的,而不是数组中的索引和元素,bar
的可枚举键和值被扩展到 foo
。在这里,bar
属性的 集合 被传播——不仅仅是一个单一的值,因此它不符合运算符的定义。
1 Object rest/spread properties 目前处于 ECMAScript 的第 3 阶段提案中,很可能会在不久的将来添加
2 除了语义之外,解构赋值作为运算符的另一个问题是 the language specification 将其定义为 补充语法 -- 不是补充运算符,这是理所当然的。它不是独立的,因为这行不通:
const ...bar = [1, 2, 3, 4];
它是上下文相关的,只允许在语言的语法、左侧表达式的对象文字和数组文字中使用。它也是 改进左侧表达式 解释的语法。同样,这是向语言添加新 syntax 的扩展,是对现有语法的改进。这重申了规范的论点。