为什么这样做:
a = []
a.push(['test']);
(function() {alert('poop')})()
但这会给错误“数字不是函数”:
a = []
a.push(['test'])
(function() {alert('poop')})()
唯一的区别是第2行末尾的分号。我已经写了很长时间的JavaScript了。我知道自动分号插入,但我无法弄清楚会导致此错误的原因。
答案 0 :(得分:12)
看看这个链式函数调用的例子。
a.push(['test'])(function() {alert('poop')})()
看起来很熟悉?这就是编译器/解释器查看代码的方式。
<强>详细强>
以下是用于描述调用表达式的语法的一部分。
CallExpression : MemberExpression Arguments CallExpression Arguments CallExpression [ Expression ] CallExpression . IdentifierName
基本上每个组(...)被视为原始 MemberExpression a.push
的参数。
a.push (['test']) // MemberExpression Arguments
(function() {alert('poop')}) // Arguments
() // Arguments
或者更正式
CallExpression( CallExpression( CallExpression( MemberExpression( a.push ), Arguments( (['test']) ) ), Arguments( (function() {alert('poop')}) ) ), Arguments( () ) )
答案 1 :(得分:3)
我不是Javascript专家(甚至是新手:),但如果你将第二行和第三行结合起来,它仍然看起来语法上有效:
a.push(['test'])(function() {alert('poop')})()
那是试图将a.push(['test'])
的结果视为函数,将函数传递给它...然后将结果作为函数调用。
我怀疑如果两个语句可以在语法上合并为一个语句,则需要使用分号,但这不是你想要的。
答案 2 :(得分:1)
由于
a.push(['test'])(function() {alert('poop')})()
是一个有效的JavaScript表达式。如果某些相邻的行可以粘在一起形成一个有效的JavaScript表达式,那么您的JavaScript引擎将将它们粘在一起。
虽然它是一个有效的JavaScript表达式,a.push
返回一个不是函数的数字,当你尝试调用一个不是函数的东西时,它会返回你看到的错误。
答案 3 :(得分:1)
a.push(['test'])
将返回数组的长度,一个数字。如果没有分号,编译器将解释自调用函数的开括号,就像您尝试将该数字作为带参数的函数执行一样。假设它返回的长度为7,那么基本上这里发生的事情就像你写的那样:
7 (function() {alert('poop')})();
因此错误“数字不是函数”,因为它不知道如何将7作为函数调用。
答案 4 :(得分:1)
有些情况下,white space不需要作为令牌分隔符,但仅用于提高可读性:
空格字符用于提高源文本的可读性并将标记(不可分割的词汇单元)彼此分开,但在其他方面无关紧要。任何两个令牌之间可能会出现空白区域,但不能出现在任何其他类型的令牌中。
在这种情况下,a.push(['test'])
和(function() {alert('poop')})()
之间的空格不适用于令牌分隔符,因此无关紧要。所以它等同于:
a.push(['test'])(function() {alert('poop')})()
由于a
引用长度为0的空数组,因此调用a.push(['test'])
会将一个元素追加到a
并返回更新后的a.length
值,即{{1} }}:
1
其余的都是历史。
答案 5 :(得分:0)
a.push(['test'])
会返回一个数字。
然后,您尝试将该号码作为函数调用function() {alert('poop')}
作为唯一参数。
因此您的错误number is not a function
。
答案 6 :(得分:0)
a.push()的结果是返回数组的大小,在本例中为1.函数周围的括号使得Javascript解析器认为您正在尝试调用:
1( function() {alert('poop')} )()
或者您尝试使用匿名函数作为参数调用名为1
的函数,然后将return作为函数执行。