ECMAScript文档中的SpreadElement是什么?它和MDN上的Spread语法是一样的吗?

51

ECMAScript规范中,描述了SpreadElement

SpreadElement[Yield]:
...AssignmentExpression[In, ?Yield]

这与 Spread语法 相同吗?

Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.

Syntax

For function calls:

myFunction(...iterableObj);

For array literals:

[...iterableObj, 4, 5, 6]

你是否看过MDN文档中描述的内容?

SpreadElement和展开语法的使用案例是什么?如果SpreadElement和展开语法不同,它们具体有哪些区别?


1
对于函数调用,我个人会说它是 REST 参数而不是扩展运算符。然而它们都可以实现几乎相同的目的和方式。 - choz
2
@choz:嗯,如果我们想要精确的话,在调用中应该是展开,而在定义中则是剩余:x = f(a, ...b) 展开 bfunction f(a, ...b) 将其余参数收集到 b 中。数组也是一样的:在字面量中 x = [a, ...b] 是展开,在解构赋值 [a, ...b] = x 中则是剩余。 - Amadan
1
@Amadan 在 x = f(a, ...b) 中,b 必须是一个可迭代对象。我认为这仍然被称为 spread。而 function f(a, ...b),它使得 b 必须出现在最后,并且能够包含其余的参数。因此,我称之为 Rest parameters - choz
2
是的,整个重点在于展开语法并不是一个“运算符” - Bergi
@guest271314: 哦,Amadan已经向您解释了spread和rest的区别?顺便说一下,我们已经有了 那个问题 - Bergi
显示剩余4条评论
4个回答

110
“展开运算符”这个术语有点像一个“大伞词”,它指的是ES6中各种句法结构,它们都看起来像...x。MDN也是如此。
然而,这是误导性的,因为...不是一个运算符(至少在ECMAScript规范使用“运算符”一词的意义上不是)。它不会产生一个可以用于进一步计算的值。我更愿意将其与其他标点符号进行比较,例如,;(它们也有点相关,但在不同的上下文中具有不同的意义)。
“展开运算符”这个术语可能指的是:
- 展开元素,var arr = [a, b, ...c];:展开元素将可迭代对象(c)展开到新数组中。它相当于类似 [a,b].concat(c) 的东西。 - 剩余参数,[a, b, ...c] = arr;:在解构中,...结构的作用相反:它将剩余元素收集到一个数组中。这个例子等同于
a = arr[0];
b = arr[1];
c = arr.slice(2);

请注意,这只是一个近似值,因为解构可以用于任何可迭代值,而不仅仅是数组。

  • fun(a, b, ...c):在规范中,这个结构实际上没有名称。但它的工作方式与展开元素非常相似:它将可迭代对象扩展到参数列表中。
    它相当于func.apply(null, [a, b].concat(c))

    缺乏正式名称可能是人们开始使用“展开运算符”的原因。我可能会称之为“展开参数”。

  • 剩余参数:function foo(a, b, ...c):与 rest 元素类似,剩余参数收集传递给函数的其余参数,并将它们作为数组在c中提供。ES2015 规范实际上使用术语BindingRestElement来引用此结构。

  • 相关问题:


    :如果我们非常严谨,甚至要根据规范区分变量声明(var [a, b, ...c] = d;)和简单赋值([a, b, ...c] = d;)。


    1
    顺便提一下,“...不是运算符”这部分,我为此创建了一个CW规范(如果你还没有看到的话):https://dev59.com/4VcP5IYBdhLWcg3wDWRq。虽然有点晚了,但是可以解释得更详细一些。 - Andrew Li

    1
    "

    SpreadElement是ES6语法中用于数组字面量中展开运算符及其参数的名称:

    "
    SpreadElement[Yield]:
        ... AssignmentExpression[In, ?Yield]
    

    所以,在 [a, b, ...c] 中,SpreadElement...c;扩展 "运算符" 是 ...。(引号是因为它不像 - 那样是真正的运算符。)
    在函数调用中使用的语法规则名称将不同,因为它是不同的语法上下文(它只是一种 ArgumentList)。

    1
    不,SpreadElement是ES6规范中的语法规则,正如我上面所解释的那样,它涵盖了不仅仅是...运算符。MDN将...称为“运算符”,因为在上下文中很清楚其含义,只有学究才会坚持使用“语法结构”或其他类似术语。 - Amadan
    1
    你在逗我吗?“为什么MDN使用运算符这个术语?”上面已经回答了:“MDN将...称为'operator',因为在上下文中很清楚它的含义,只有学究才会坚持使用语法结构或其他东西。”“SpreadElement覆盖了什么?”上面已经回答了:“[a, b, ...c]中的SpreadElement...c;spread 'operator'是...。”“什么是'学究'?”去查字典。 - Amadan
    4
    @guest271314 - ECMA-262 是语言规范,所以它是权威的。MDN 是一个公共维基,任何人都可以为其做出贡献,它不是任何事情的权威。对于记录(和学究),...标点符号,是 SpreadElement 的一部分。 - RobG
    @Amadan "你是在逗我吗?" 真的吗?你是为了更清楚地询问问题吗?如果你不想提供更多细节,那么也许你应该删除你的回答?或者,只需说你的回答就是你的回答,就这样。当然,这由你决定。你在评论中提供了比实际回答更详细的信息,链接为 https://dev59.com/pFoU5IYBdhLWcg3wvIuq#vsrnnYgBc1ULPQZFjBIT. 没有,没有“逗弄”这一说。名字叫人并不是必要的交流方式。 - guest271314
    1
    @guest271314:您可能想看一下关于...标记如何构成运算符的此已删除问题的评论。 - Bergi
    显示剩余7条评论

    0
    另一个用例是替换Object.assign方法:
    // assign的天真用法——覆盖o中共享的属性:
    Object.assign(o, defaults); 
    
    /* non-naive use of assign—prevents shared properties in o from being 
       overwritten */ 
    o = Object.assign({}, defaults, o);  
    

    或者,使用展开运算符:

    o = {...defaults, ...o} 
    

    这是ES2018中最重要的功能之一。
    let position = { x: 0, y: 0 };  
    let dimensions = { width: 100, height: 75 };  
    let rect = { ...position, ...dimensions };  
    rect.x + rect.y + rect.width + rect.height // => 175 
    

    -MDA


    0
    通常,三个点被称为“扩展运算符”,但当作为函数参数的一部分时,它被称为“剩余运算符”(MDN链接)。当你不确定有多少参数传递给函数时,可以使用剩余运算符。剩余运算符将所有传递给函数的参数分组成一个数组。以下是一个示例:
    function getNames(...names){
      console.log(names) // Output: ["Raul", "Chris", "Megan"]
    }
    
    getNames("Raul", "Chris", "Megan")
    

    如果您想要将已知的参数组合和一组剩余参数传递给函数,您需要确保剩余运算符是创建函数时列出的最后一个参数。例如:
    function getNamesInClass(teacher, room, ...students){
      console.log(teacher) // Output: "David"
      console.log(room) // Output: "3B"
      console.log(students) // Output: ["Raul", "Chris", "Megan"]
    }
    
    getNamesInClass("David", "3B", "Raul", "Chris", "Megan")
    

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