已编辑:表达式function foo() {return 20;}, foo()
是console.log
的单个参数。
此:
console.log((function foo() {return 20;}, foo()));
不起作用,我得到ReferenceError
,因为尚未定义foo
。
为什么?
答案 0 :(得分:9)
console.log(function foo() {return 20;}, foo());
在这段代码中,您要传递一个名为 (foo
)的函数作为console.log
的参数。得到它了?您从未声明函数foo
,只是将其作为参数传递。在javascript中,函数声明和函数表达式具有相同的语法,因此造成混淆。
也就是说,传递一个名为 (而不是 anonymous )的函数几乎总是无用的。您的代码与此等效:
console.log(function () {return 20;}, foo());
其中function () {return 20;}
是匿名函数,与命名函数相反。而且,匿名函数在JS中的使用非常广泛,因为同样,命名函数表达式中的名称几乎没有用。
答案 1 :(得分:3)
更新
我看到您编辑了原始问题。由于您实际上只向console.log()
传递了一个参数,因此我相信在这种情况下,您收到ReferenceError的原因是因为当您使用这样的逗号时,该函数语法被视为函数表达式而不是函数声明。因此,它是一个命名函数,但不是声明的函数,并且对于foo()
表达式仍然不在范围内。
有关声明和语句与表达式的更多信息,请参见http://2ality.com/2012/09/expressions-vs-statements.html,尤其是“函数表达式与函数声明”部分。
要清楚,这(单独一行)将是一个函数声明:
function foo() {return 20;})
这是在定义变量并将其分配给命名函数 expression :
const foo = function foo() {return 20;})
在您的代码中,实际上您正在创建一个函数 expression ,即使它看起来像是一个函数 declaration 。
可以在允许使用语句或表达式的任何位置定义函数。因此,您的代码的语法是有效的,但是它无效,因为表达式的作用域仅限于定义它们的位置。在这种情况下,第二个参数无法访问第一个参数中的foo
函数。类似于使用let
或const
时,变量无法在其块之外访问,例如:
if (someCondition) {
const foo = () => 20
console.log(foo()) // works
}
console.log(foo()) // doesn't work: Uncaught ReferenceError: someCondition is not defined
因此,如果您需要在console.log()
的参数中调用函数,则需要在console.log()
语句之外声明外部,例如:
function foo() {return 20;}
console.log(foo());
或者,就像其他人提到的那样,您可以使用IIFE(立即调用的函数表达式),因为它不会尝试从console.log()
的第二个参数位置访问该函数(它只涉及一个参数):
console.log((function foo() {return 20;})())
...但是实际上,这是对IIFE的不良使用;没有必要在这里这样做。
答案 2 :(得分:2)
使用console.log
的每个“日志”将输出在调用console.log
的范围内注册的值。
在您的情况下,您正在console.log
的调用内定义一个函数,此命名函数将仅在其中定义。 您需要在console.log
之外定义函数,以便输出其值。
第二个参数的行为类似于第一个参数,并将在全局范围内搜索值。它无法查找第一个参数中定义的值。