为什么这是一个有效的JavaScript函数定义?太奇怪了(但它肯定跑不了)

为什么这是一个有效的JavaScript函数定义?太奇怪了(但它肯定跑不了),javascript,Javascript,我刚刚发现我可以用JavaScript定义一个函数,如下所示: function a(){ ([]()) } 同样,这种方法也是有效的函数定义 function a(){ ([]())()()([])([]) } 它看起来甚至不像一个有效的语法,不是吗?但是,编译器在定义它们时不会责怪它们。(调用()肯定会在以后导致错误) 空数组的函数?一个空数组的函数,还是什么?我甚至无法理解,在JavaScript编译器中将其定义为函数是如何被认为是有效的 如果您好奇的话:并非所有这些类型的函数

我刚刚发现我可以用JavaScript定义一个函数,如下所示:

function a(){ ([]())   }
同样,这种方法也是有效的函数定义

function a(){ ([]())()()([])([])   }
它看起来甚至不像一个有效的语法,不是吗?但是,编译器在定义它们时不会责怪它们。(调用()肯定会在以后导致错误)

空数组的函数?一个空数组的函数,还是什么?我甚至无法理解,在JavaScript编译器中将其定义为函数是如何被认为是有效的

如果您好奇的话:并非所有这些类型的函数定义都能通过编译器。您可以尝试在下面定义它

function a(){ ([]())()()([])([]){}   }
JS编译器不允许您定义它


我知道函数将无法调用,但我想知道,我可以定义它。所以我很想知道为什么这个定义是有效的。

[]
创建了一个空数组。它不是一个函数,所以通过像调用
[]()
那样调用它,将其视为一个函数,将产生运行时错误,但它在语法上没有任何无效之处

用括号括起来,
[]
([])
在单独使用时没有任何效果,但同样是有效的语法。

尝试运行
a()
,您将得到一个运行时错误

问题是,当您定义一个函数(就像您所做的那样)时,该函数显然不会执行,因此不会报告任何运行时错误(因为引擎只有通过实际运行该函数才能知道运行时错误)


编辑: 针对作者的评论,想象一下这个功能:

function a(){ (alert()) }
function g(){return f;}
这在语法上与第一个函数相似。但是,此函数非常好-没有运行时错误

这就是为什么引擎允许您定义这样的函数。为了让引擎捕捉到
函数a(){([])}
中的问题,它必须做出推断“
[]
是一个数组,不可调用,因此此函数生成一个错误”。但是,调用不可调用的对象是一个运行时错误(TypeError),因此引擎不会进行上述推断,因为这将试图在编译时捕获运行时错误

注意:在其他语言中,调用不可调用对象不一定是运行时错误。在大多数严格类型语言中,这是一个编译时错误。如果你用Java
int[]x;x(),将生成编译时错误


至于第二个函数,你需要理解高阶函数的概念。如果你不知道那是什么,我会在这里做一个简单的解释

想象一下:

function addone(x){return x+1;}
function f(){return addone;}
现在,如果运行
f()(1)
,这相当于
addone(1)
,即
2

现在
f
是一个二阶函数,您可以定义一个三阶函数:

function a(){ (alert()) }
function g(){return f;}
然后
g()()(1)
又是
2
。如果需要,可以定义第一百阶函数。虽然在实际代码中,您很少需要超过二阶的代码

现在回到OP中的第二个函数:

function a(){ ([]())()()([])([])   }
您正在尝试将
[]
作为五阶函数运行,这在语法上非常好。同样,检查
[]
是否实际上是一个五阶函数是运行时的事情。

请记下。 1) JavaScript函数返回未定义的(如果没有return语句define),即使函数中没有任何内容。 2) 类似的()([])([])是有效的。因为没有任何语法错误。函数内部的代码在验证程序内部针对语法错误进行验证,例如()之后不应有代码,除了半彩色;或()等。所有类型错误将仅在执行时验证


3) 这是有效的,但当您调用此函数时,它将抛出未捕获的TypeError

TypeError:[]不适用于被否决的人,请留下您的评论,说明为什么您认为值得被否决。阅读更多内容后,您基本上是在括号中执行一个数组(第一个示例),然后再次尝试执行它。我在寻找一个关于“为什么编译器没有失败?”的解释,是什么使它有效和可编译。任何PrimaryExpression都可以是CallExpression的被调用方,包括数组初始值设定项。看见如果你想知道为什么像这样的工作,我建议你仔细看看规范。在第二个函数中,
([])
实际上是一个函数调用,嗯,
([])([])
在非函数之后,在语法方面就没有什么意义了。在这种情况下,
([])
不是在私有作用域中包装数组吗?我发现我可以将
([])([])
放在一个非函数后面,并根据需要多次嵌套它。规范允许它。@taxicala:
(…)
不创建作用域。实际上我把它当作了一个模棱两可的问题。我确实想说“为什么编译器允许我们用这些语句定义函数”。当然它不会运行,但是编译器在定义它的时候并没有抱怨什么。不过我一开始就把它弄得不清楚。似乎人们认为我的意思是它是可调用的。不,我的意思是“能够定义它”。