这可能是一个愚蠢的问题。我用谷歌搜索,但找不到答案。不允许将变量声明作为函数的参数,如下所示。
function t(a) {
alert(a);
}
t(var x = 1); // Uncaught SyntaxError: Unexpected token var
t(let x = 1); // Uncaught SyntaxError: missing ) after argument list
t(x = 1); // working fine and later I am able to access x also
console.log(x); // printing 1
但是如下所示,允许函数声明作为函数的参数。
function callback(str, f1, f2) {
if(str == "")
f1();
else
f2();
};
callback("", function b1() { alert("empty") }, function b2() { alert("not empty") }); // working fine
b1(); // Throwing error Uncaught ReferenceError: b1 is not defined
任何人都可以帮助我理解
答案 0 :(得分:9)
好问题!我将其分为几部分。由于您的问题涉及多个深层主题,因此这里将有大量 可供Google搜索的材料。
声明是语句。它们没有值,因此不能成为参数。这段代码...
let a = 1
...没有价值,意味着这些都不起作用:
doStuff(let a = 1)
let b = (let a = 1)
(let a = 1) + 5
名称a
或a + 5
或f(a)
是表达式,与声明不同,表达式具有价值。但是a
本身的声明没有。
请注意,您对此的直觉并不荒谬:在其他语言中,let a = 1
是一个表达式,其结果为1
。不在Java中。
,但是function
关键字 具有值:它定义的Function
对象。与变量(为方便起见,它们是语言构造)不同,Functions
是正在运行的程序中存在的实际对象。我们说函数是一流的对象。
您可以完成所有这些操作:
doStuff(function f() {})
let a = function f() {}
let b = (function f() {}) + 5 // the result of this is funny
回到您的示例,然后:
callback(
"", // a String object
function b1() { alert("empty") }, // a Function object
function b2() { alert("not empty") } // a Function object
);
类似于此:
function b1() { alert("empty") }
function b2() { alert("not empty") }
callback("", b1, b2)
但不完全是。让我们谈谈范围。
诸如变量或函数之类的名称的作用域是具有该定义的代码部分。
例如:
// Top-level scope:
let a = 1
if (a == 1) {
// Inner block scope:
let b = 2
console.log(a, b) // 1, 2
}
console.log(a, b) // 1, undefined
合并范围位于较大的合并范围内。内部范围可以访问周围的范围(因此a
和b
在块内可见),但反之则不行(因此b
在外部不可见)。
在通话中创建function
对象时...
f(function a() { })
...它们被困在一个内部范围内,无法从外部引用。
在示例代码中,您注意到声明a
可以这样:
f(a = 5)
这是...不幸的。确实是Javascript历史的产物。在现代代码中,应始终使用let
或const
定义变量。
那为什么行得通呢?有两个原因。首先,因为它是一个赋值,而不是声明。像这样:
let x = 1
f(x = 2)
赋值是表达式。它们评估为分配的值。 x = 2
的值为2
,并且x
会产生副作用。
第二个原因是不幸的。当您避免使用let
,var
或const
关键字时,便隐式使用了global
范围。
这是所有作用域的源泉,可以从代码的任何位置访问存在于其中的名称。所以,如果您只是这样做...
f(a = 5)
...在当前范围的任何地方都没有声明a
时,它在全局范围中隐式声明,并且赋值发生。可以这样看(伪代码):
global let a
f(a = 5)
那当然是无效的Javascript。但是你明白了。