一开始我也很难理解这一点。这就是我如何通过一击一击达到清晰。这是我在堆栈上的第一篇文章,请原谅我对此啰嗦。
让我们看一个返回字符串的非常基本的函数:
function fun() {
return 'Hi!';
}
如果我们在没有调用括号的情况下记录上述函数,控制台只会记录对该函数的引用:
console.log(fun); //logs ---> [Function: fun]
如果我们再次记录它,但带有调用括号:
console.log(fun()); //logs ---> Hi!
函数的调用等于它的返回值:
console.log(fun() === 'Hi!'); //logs ---> true
因此,在此基础上,让我们重写我们的函数,在其中声明另一个返回字符串的函数。外部函数将返回内部函数的调用:
function funAgain() {
function innerFun() {
return 'Hello there!';
}
return innerFun();
}
因此,在 funAgain (innerFun() === 'Hello there!') 的范围内,计算结果为 true,因此当我们将 funAgain 调用记录到控制台时:
console.log(funAgain()); //logs ---> 'Hello there!'
但是,如果我们在外部函数的 return 语句中去掉调用 innerFun 的括号会怎样?
function funAgain() {
function innerFun() {
return 'Hello there!';
}
return innerFun;
}
console.log(funAgain()); //logs [Function: innerFun]
返回函数 ITSELF。虽然这实际上不是全部,但我们可以想到 (funAgain() === innerFun) 显然,由于范围问题,您实际上无法在实践中运行此比较(innerFun 不能存在于 funAgain 的调用之外) . 但!让我们这样想一下。这意味着如果我们在一个变量中捕获 funAgain 的返回值:
var innerFunCaptured = funAgain();
console.log(innerFunCaptured); // logs [Function: innerFun]
从概念上讲,我们有 (innerFunCaptured === innerFun) ...
因此,现在我们的变量已绑定到内部函数,我们可以通过向变量添加括号来调用该内部函数。
console.log(innerFunCaptured()); //logs ---> 'Hello there!'
当我在谈论上面的“整个故事”时,我遗漏的是内部函数与变量的绑定是外部函数调用的结果,所以实际上绑定不仅包括 innerFun 本身,还包括它的环境是在包含通过调用外部函数传递的任何潜在参数中创建的,这使我们能够...
再次重写外部函数和内部函数,使它们现在具有交互的参数:
function funOnceMore(greetingPartOne) {
function innerFun(greetingPartTwo) {
return greetingPartOne + ' ' + greetingPartTwo;
}
return innerFun;
}
如果我们用参数记录 funOnceMore 会怎样。
console.log(funOnceMore('Hello')) //logs ---> [Function: innerFun]
同样,innerFun 本身被返回。但是我们传递的参数 greetingPartOne 呢?好吧,它通过了,但是由于在 funOnceMore 中从未调用过 innerFun,因此从未以任何有意义的方式使用 greetingPartOne。我们必须弄清楚如何调用 innerFun!答案:我们需要将它绑定到一个变量,就像我们在上一步中所做的那样。
var innerFunCapturedAgain = funOnceMore('Hello')
现在 innerFunCapturedAgain 拥有 innerFun 和 funOnceMore 的环境以及我们传递给它的参数“Hello”。
所以现在我们可以通过在innerFunCapturedAgain 上加上括号来调用innerFun,这些括号将封装我们传递给innerFun 的greetingPartTwo 的参数。
console.log(innerFunCapturedAgain('there!')) //logs ---> 'Hello there!'