180

为什么这在 Node.js 控制台中有效(在 4.1.1 和 5.3.0 中测试),但在浏览器中不起作用(在 Chrome 中测试)?

此代码块应创建并调用一个匿名函数来记录Ok.

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

此外,虽然上述方法Node.js 中有效,但这不起作用:

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

也不是这个:

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

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

4

4 回答 4

238

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

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

相当于IIFE

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

这在 Node.js 中有效但在 Chrome 中无效的可能原因是它的解析器将其解释为自执行函数,因为

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

工作正常Node.js。这是一个函数表达式,Chrome、Firefox和大多数浏览器都是这样解释的。您需要手动调用它。

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

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

((n) => {
  console.log('Ok');
})()
于 2016-01-04T10:53:57.223 回答
18

没有括号,这些都不应该工作。

为什么?

因为根据规范:

  1. ArrowFunctionAssignmentExpression下
  2. CallExpressionLHS必须是MemberExpressionSuperCallCallExpression

所以ArrowFunction不能在CallExpression的 LHS 上。


这实际上意味着应该如何解释,它与赋值运算符等=>在同一级别上工作。=+=

意义

  • x => {foo}() 不会变成(x => {foo})()
  • 解释器试图将其解释为x => ({foo}())
  • 因此它仍然是一个SyntaxError
  • 所以解释器决定(肯定是错误的并抛出一个SyntaxError

Babel 上也有一个关于它的错误

于 2016-01-04T11:09:05.533 回答
2

您看到此类问题的原因是控制台本身试图模拟您当前定位的上下文的全局范围。它还尝试从您在控制台中编写的语句和表达式中捕获返回值,以便显示为结果。举个例子:

> 3 + 2
< 5

在这里,它就像一个表达式一样执行,但是您已经将它写成一个语句。在普通脚本中,该值会被丢弃,但在这里,代码必须在内部被破坏(例如用函数上下文和语句包装整个return语句),这会导致各种奇怪的效果,包括您遇到的问题。

这也是为什么脚本中的一些裸 ES6 代码可以正常工作但在 Chrome 开发工具控制台中不能正常工作的原因之一。

尝试在 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 语义交互的限制,这有时很难或不可能解决。

于 2016-07-15T09:02:09.993 回答
1

我问了这样一个问题:

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

这是凯尔辛普森的回答:

箭头函数一个表达式,但我们需要围绕“运算符优先级”(排序)的括号 b/c,以便调用箭头 IIFE 的最终括号适用于整个函数,而不仅仅是其主体的最后一个标记.

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

对比

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

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

于 2020-06-12T15:45:38.343 回答