通过示例了解JavaScript闭包
让我们从理解另一个名为闭包的JavaScript基础开始。
闭包简介
闭包被认为是JavaScript中的一个高级概念。完全理解这个概念可能需要一段时间。但是,不要担心。正如您在本系列的前几篇文章中了解的执行上下文、范围和范围链的基础知识一样,它对您来说会简单得多。
让我们从一个简单的代码示例开始,
function sayHello(msg) {
return function(name) {
console.log(`${name}! ${msg}`);
}
}
这里我们有一个函数sayHello(),它将消息作为参数。在JavaScript中,函数可以返回另一个函数。sayHello()返回一个函数,该函数将name作为参数,并在控制台中记录名称和消息。sayHello()中的函数称为内部函数,sayHello()可以称为外部函数。
很公平。我们如何调用它们?在这里,
var messageFor = sayHello('Hello, there!');
console.log(messageFor('Jack'));
正如sayHello()返回一个函数,变量messageFor指向一个函数。在下一行中,我们调用messageFor传递值“Jack”。它记录以下输出,
Jack! Hello, there!
但是,我们有几个问题知道
-
sayHello()的内部函数如何获得对msg变量的访问权限?这怎么可能? - 这里的
作用域呢?msg变量绝不在内部函数的范围内。那它是怎么工作的?
答案是,它在一个名为闭包的JavaScript功能的帮助下工作
有点总结
现在,我们意识到,
- 有一种称为
全局执行上下文和函数执行上下文的东西。 - 当JavaScript程序运行时,会创建一个全局执行上下文。
- 调用函数时,会创建函数执行上下文
- 所有函数执行上下文都指及其外部环境,即创建当前运行函数的函数的执行上下文。
- 使用外部引用,JavaScript引擎确定变量的可访问性。这称为
作用域。 - 可以通过遍历导致全局执行上下文的作用域链来找到变量的作用域。
我们以前见过这张照片,
闭包分析
在JavaScript中,一个函数可以嵌套在另一个函数中。嵌套的函数称为内部函数。这个内部函数可以访问外部函数上下文中定义的变量。它是通过闭包完成的。所以,是内部函数创建了外部函数的闭包。
让我们更详细地了解上面示例的执行步骤。这又是代码
function sayHello(msg) {
return function(name) {
console.log(`${name}! ${msg}`);
}
}
var messageFor = sayHello('Hello, there!');
console.log(messageFor('Jack'));
- 创建一个全局执行上下文。在其
执行阶段,调用函数sayHello()
var messageFor = sayHello('Hello, there!');
- 为
sayHello()创建了一个函数执行上下文,并将其添加到执行堆栈中。请注意,它有一个名为msg的参数,它将在其执行上下文中可用。
function sayHello(msg) {
}
-
sayHello()返回另一个函数并弹出执行堆栈
function sayHello(msg) {
return function(name) {
console.log(`${name}! ${msg}`);
}
}
sayHello()返回一个内部函数。这意味着,内部函数将创建一个对外部函数(sayHello())执行上下文的闭包。这样,它也将拥有对外部函数变量的所有访问权限。在这种情况下,它是msg。
- 接下来,全局执行上下文调用
messageFor('Jack')。这只不过是最后一步中返回的内部函数。
console.log(messageFor('Jack'));
此调用将创建一个新的函数执行上下文。当我们将Jack作为参数传递时,它将在其执行上下文中可用。但请记住,它也可以访问上述步骤中解释的msg。
这就是闭包如何帮助保留对父级执行上下文的访问,即使它已经被执行并从执行堆栈中删除。
这是一个引人注目的概念。我希望它更容易理解。还没有?好吧,让我们直观地看到所有这些发生,
内部函数在外部函数的执行上下文上创建了一个名为闭包作用域的特殊范围。这就是闭包作用域的样子(红色边框),
试试这个例子
你认为下面会是什么?
function myMultiplier(x) {
return function inner(y) {
return x * y;
}
}
然后调用函数,例如,
var multiplyOf5 = myMultiplier(5);
var multiply5x4 = multiplyOf5(4);
console.log(multiply5x4);
我肯定你明白了!是的,内部函数将可以访问父函数(myMultiplier())执行上下文的变量。内部函数现在在范围内有两个变量,i、e、x和y。
在执行阶段,x和y的值分别为5和4。这些乘法的结果是20。现在不是很简单吗?