ES6立即调用箭头功能


152

为什么这在Node.js控制台(在4.1.1和5.3.0中进行了测试)中不能运行,而在浏览器中(在Chrome中进行了测试)中却不起作用?该代码块应创建并调用一个记录日志的匿名函数Ok

() => {
  console.log('Ok');
}()

此外,虽然上述作品中的节点,这并不工作:

n => {
  console.log('Ok');
}()

也没有:

(n) => {
  console.log('Ok');
}()

奇怪的是,当添加参数时,它实际上会SyntaxError在立即调用的部分抛出a 。


8
好问题。两个参数化版本均与Babel配合使用
CodingIntrigue,2016年

2
出于兴趣,(n => { console.log("Ok"); })();行得通吗?
CodingIntrigue'1

是的,(n => { console.log("Ok"); })()甚至可以在Chrome开发者控制台中使用
-XCS

因此,三年后,答案是?确定要接受以下三个答案之一吗?
joedotnot

@joedotnot我没有一个明确的答案,主要是它在Node.js中是一个怪异的实现。Node.js在第一个版本的最新版本中似乎无法正常工作了。
XCS

Answers:


200

您需要使它成为函数表达式,而不是不需要名称的函数定义,并使它成为有效的JavaScript。

(() => {
  console.log('Ok');
})()

相当于IIFE

(function(){
   console.log('Ok')
})();

而且它可能在Node.js中而不是在chrome中起作用的可能原因是因为其解析器将其解释为自执行函数,因为

function() { console.log('hello'); }();

Node.js这是一个函数表达式以及chrome和firefox中,可以正常工作,并且大多数浏览器都以这种方式对其进行解释。您需要手动调用它。

告诉解析器期望函数表达式的最广泛接受的方法只是将其包装在parens中,因为在JavaScript中,parens不能包含语句。此时,当解析器遇到function关键字时,它知道将其解析为函数表达式而不是函数声明。

关于参数化版本,这将起作用。

((n) => {
  console.log('Ok');
})()

4
第一个示例可以工作Node.js并实际记录该值。我的问题是为什么行得通?当我添加参数时为什么没有呢?
XCS

1
我对IIFEs非常熟悉,并且知道如何修复我的代码。我只是很好奇为什么为什么IIFEn添加参数时我不起作用,即使没有参数也可以。
XCS

3
我没有拒绝投票,但是问​​题是为什么当没有参数的完全相同的定义起作用时,为什么参数化版本在Node中不起作用-它不是问匿名函数的Node / Chrome实现之间的区别
CodingIntrigue

1
如前所述,这是一个好知识,但它不能回答问题,-当没有参数的完全相同的定义起作用时
jkris

但是,等效于function(){}()in箭头功能是什么?如果我希望函数对象公开的函数表达式可以防止这种情况。
dabadaba

18

没有括号,所有这些都不起作用。

为什么?

因为根据规范:

  1. ArrowFunction列在AssignmentExpression
  2. CallExpressionLHS必须是MemberExpressionSuperCallCallExpression

因此,一个ArrowFunction不能在一个的LHS CallExpression


什么这实际上意味着在如何=>应解释是,它可以在同一水平排序为赋值运算符=+=等等。

含义

  • x => {foo}() 没有成为(x => {foo})()
  • 解释器尝试将其解释为 x => ({foo}())
  • 因此它仍然是一个SyntaxError
  • 因此,解释器确定(必须输入的错误,并引发SyntaxError

Babel也有一个关于的错误。


这些是有效的观点,但是如果我尝试将第一个有效的版本替换为:() => ({console.log('Ok')}())它不再起作用。因此,它并不是真的那样解释。
XCS

@Cristy这不是有效的Arrow Function产品。它认为您正在尝试创建带有Object文字的Object(用括号括起来),console.log(...)并且不是有效的键名。
thefourtheye

@Cristy:是的,我认为上面的解释部分(“含义”位)可能不太正确,但是据我所知,规范部分是正确的。同时,这也是我从V8得到错误:SyntaxError: Unexpected token ((在指向(()结尾,而不是(console.log(...))。
TJ Crowder

@TJCrowder你是对的,我会指出这一点,因为它会更改错误消息,并且我要说的内容没有得到传达(即(,在尝试寻找有效解释并竭尽全力后,导致解释器放弃了“这肯定是错误的,那么”),这可能是错误的,因为反正我不知道解释是如何真正写
保罗S.

我想知道在这个位置它是否不是有效的令牌,它不会尝试插入分号吗?
thefourtheye

2

之所以会出现这样的问题,是因为控制台本身试图模仿您当前定位的上下文的全局范围。它还尝试捕获您在控制台中编写的语句和表达式的返回值,以便将其显示为结果。举个例子:

> 3 + 2
< 5

在这里,它好像是一个表达式一样执行,但是您已经把它写成是一个语句。在普通脚本中,该值将被丢弃,但是在这里,必须对代码进行内部处理(例如,将整个语句包装在函数上下文和return语句中),这会引起各种奇怪的影响,包括您遇到的问题。

这也是脚本中的一些裸露ES6代码可以正常运行,但不能在Chrome Dev Tools控制台中运行的原因之一。

尝试在Node和Chrome控制台中执行此操作:

{ let a = 3 }

在Node或 <script>标签中,它工作正常,但在控制台中,它给出Uncaught SyntaxError: Unexpected identifier。它还为您提供了到源的链接VMxxx:1,您可以单击该链接的形式来检查评估的源,其显示为:

({ let a = 3 })

那么为什么要这样做呢?

答案是它需要将您的代码转换为表达式,以便将结果返回给调用方并显示在控制台中。您可以通过将语句包装在括号中来做到这一点,使其成为表达式,但也使上面的语句在语法上不正确(表达式不能具有语句块声明)。

控制台确实通过精通代码来尝试解决这些极端情况,但是我认为这超出了此答案的范围。您可以提交一个错误,看看是否可以解决这些问题。

这是一个非常相似的例子:

https://stackoverflow.com/a/28431346/46588

使代码正常工作的最安全方法是确保可以将其作为表达式运行并检查 SyntaxError源链接以查看实际的执行代码,然后从中反向解决方案。通常,它是指一对放在战略上的括号。

简而言之:控制台尝试尽可能准确地模拟全局执行上下文,但是由于与v8引擎和JavaScript语义的交互的局限性,有时难以解决或无法解决。


1
这就是重点,我关心参数,但不适用于参数集。
XCS

好,我明白你的意思了。区别在于Chrome Dev Tools控制台实际执行代码的方式。我将编辑答案以反映这一点。
KlemenSlavič'16

0

我问了这样一个问题:

@getify我有一个问题:要产生#IIFE模式,我们在函数声明周围使用parans将其转换为函数表达式,然后调用它。现在在箭头功能IIFE中,为什么我们需要帕兰斯?默认情况下,箭头功能不是已经是表达式吗?

这就是凯尔·辛普森的答案:

箭头函数expr,但是我们需要在括号中加上“操作符优先”(sorta)的b / c,以便调用箭头IIFE的最终括号不仅适用于整个函数,还适用于其主体的最后一个标记。

x => console.log(x)(4)

(x => console.log(x))(4)

-getify(@getify)2020年6月12日


我的问题是为什么它在某些编译器上有效而在其他编译器上无效。
XCS

这是因为不同的编译器的行为在一些细节上有所不同,就像不同的浏览器,当然具有不同的编译器
艾尔沙德Qaderi

没错,它们的行为确实有所不同,但是所有JavaScript规范都是相同的。我很好奇哪个是正确的,JS规范对此情况说了些什么,特别是没有参数但没有参数的情况下,怎么可能呢?我一直在寻找更多的技术回应。
XCS

您的示例非常明显,在第一种情况下,确实应调用console.log(x)(4)
XCS

我只是在这里猜测,但我认为这样解释是非常合理的:在箭头函数表达式中,当我们不使用参数时,必须使用括号,这对于引擎来说很清楚这是箭头函数表达式,但是当我们有一个参数的括号是任意的可能不很清楚,这样的功能和混淆的发动机,来解决我们必须把对周围的整体功能表现括号的困惑
艾尔沙德加德利
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.