为什么两个函数调用的括号之间的换行符不被视为js中的两个语句?

时间:2018-08-13 06:33:08

标签: javascript syntax

为什么在JS上进行这种不良设计?有什么特殊的理由来设计这样的自动分号?

这是我的代码,在chrome的js中不起作用:

(function(){console.log("abc");})()

(function(){console.log("123");})();

这是错误:

Uncaught TypeError: (intermediate value)(...) is not a function

我知道这段代码的正确版本是:

(function(){console.log("abc");})();

(function(){console.log("123");})();

我只想知道为什么js语法设计得如此愚蠢。历史原因?

我还将这个问题作为警告,警告大家尝试使用javascript自动分号插入,只要在需要的地方添加;,javascript的自动分号就是垃圾。它不符合您的期望。

存在的答案对我来说太复杂了,所以我问一个新的答案:

https://stackoverflow.com/a/2846298/1586797

另一个看起来不错,但无法解决问题2:

x=1

(function(){console.log("123");})()

7 个答案:

答案 0 :(得分:3)

链接的问题的答案解释了规范针对ASI的三个规则,例如this one。 tl; dr:

  • 如果它不起作用,请尝试使用分号。

  • 程序应以分号结尾。

  • 如果一条语句说“不能在此处放置换行符”,请用分号对其进行惩罚。

您的代码不满足任何条件。

  • 第一行可以返回一个函数,如果可以,则应允许该函数被调用;因此第二行开头的(不合法

  • 第一行不是程序的最后一行

  • 此处没有语法限制。

因此,没有适合您的自动分号。

因此,有人声称(f(){})()语法是很好的IIFE语法,但最好改用!f(){}()

!function(){console.log("abc");}()

!function(){console.log("123");}();

这是按预期的方式工作的,因为!仅仅抵消了函数应用程序的(丢弃)结果,并且因为!作为纯一元运算符是继续第一行的非法字符(即{ 1}}不是问题。这会触发规则1,ASI就会发生。

反对意见是,这种说法很丑陋(即,对于尚不熟悉该做法的任何人,他们花一些时间才能理解此成语中f(){}()!的目的)。

您的第二个示例在本质上是相似的:就JS解析器而言,!是一个值(它是一个整数并且不可能是一个函数的事实让它有些失落) 。看这个示例,它在语法上完全等同于您的示例:

1

这里a=function(f) { console.log("A CALLED!"); return f; } x=a (function(){console.log("123");})() # => A CALLED! 123 是一个函数,因此可以使用a作为参数来调用它;打印到控制台后,它返回function(){console.log("123");}不变;然后function(){console.log("123");}调用该返回值,同时也显示()。一切正常。因此,规则#1不会被触发,您也不需要分号。

答案 1 :(得分:2)

如果没有分号,则这些语句将被链接。您调用第一个函数,并将第二个func作为第一个函数的返回值的参数。如果第一个函数有一个函数作为返回值,那么这实际上可以工作。

扩展代码时,它变得更加明显:

repositories {
    maven()
    //other repositories...
    google()
}

最后两行变为:

var a = function(){console.log("abc");};
var b = function(){console.log("123");}
(a)()
(b)();

这等同于

(a)()(b)();

由于var x = a(); x(b); 不返回任何内容,因此无法使用a作为参数将其作为函数调用。

答案 2 :(得分:2)

b

等效于:

(function(){console.log("abc");})()

(function(){console.log("123");})();

通常称为函数curring。 对于IIFE(立即调用的函数表达式),您需要以(function(){console.log("abc");})()(function(){console.log("123");})();

结尾

有关函数循环的更多信息,请参见this post。显然,您的控制台日志功能不能用作currying函数,但是语法;是用于currying的语言的一个很酷的功能。

答案 3 :(得分:2)

您的代码可以简化为:

(function(){})()()();

此代码将得到相同的错误。

()需要一个表达式来调用。

第一个()调用(function(){}),第二个()调用(function(){})()的结果,但该结果不是函数,因此是错误的。

答案 4 :(得分:1)

如果您使用此方法,我认为这会更清楚:

x=1

(function(){console.log("123");})()

错误状态1不是函数。明确说明(function...)被视为对1的函数调用的参数:

x=1(function(){console.log("123");})()

答案 5 :(得分:1)

因为()()是self-invoking函数,而();()是两个不同的函数,所以解释器会相应地对其进行解释。

这两个代码对于解释器是完全不同的。

(function(){console.log("abc");})()(function(){console.log("123");})();

(function(){console.log("abc");})();(function(){console.log("123");})();

但是,此代码可以正常工作

var a=12
var b=10
console.log(a+b)

答案 6 :(得分:1)

长答案排序:

(function(){console.log("abc");})()

试图立即调用前面的表达式

(function(){console.log("123");})();

这将是前面的IIFE的返回值。

IIFE在缺少分号的情况下可以采取不同的行动。这就是为什么我们看到如下代码的原因:

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

请在此处查看详细说明:https://gist.github.com/khellang/8518964