理解 JavaScript 闭包
这确实是一个很难理解的概念,我花了一段时间才理解闭包是什么。以下是我理解的闭包,并附上一些图表和代码片段,以便更好地理解。
为了热身,我将从一个不涉及闭包的示例开始,然后慢慢将我的示例更改为最后涉及闭包
function add1(){
var x = 1;
var f = function(y){
return x + y;
}
return f(3);
}
console.log(add1());
这里我们有一个简单的函数叫做add1。
- 它有一个局部变量
x,其值为1 - 另一个
f被赋予函数的变量 - 此
add1函数返回函数f
因此,如果我们运行此代码,它将返回4= x1 和y= 3
由于我们有一个函数声明,并且该函数在 console.log 中被调用。执行上下文如下:
首先,我们将进入global execution context创建阶段。我们将进入creationandexecution阶段。在这个creation阶段,我们将add1函数提升到作用域的顶部;在这个execution阶段,我们将执行add1函数。
在这个执行上下文中,我们将在阶段提升变量x和 ,并且在 阶段它们都是未定义的。在阶段,被赋值,被赋值给接受参数 的函数。赋值后,它返回 函数调用;fcreationcreationexecutionx1fyf(3)
这会创建另一个名为 f 的执行上下文。在f执行上下文中,由于没有声明任何变量或函数,因此在创建阶段我们不会提升任何内容。在执行阶段,它会返回,x+y其中 的值x是通过执行上下文中的作用域链获取的add1,而 的值y是通过以下方式传入的:f(3)
因此总体x而言是1且y是3。返回4。每个 EC 执行完成后,都会将其逐一弹出堆栈。
在执行上下文中f,它返回的是x+y。 的值y在此上下文中是可获取的,即 的值3,但 的值x不是。因此,它引用外部执行上下文并检索 的值,x即1。
呼……真是太多了。希望你能够理解执行上下文和作用域。现在我们准备继续讨论一些更复杂的东西,它与闭包有关。以下是代码片段
var add = function() {
var x = 1;
var f = function(y) {
return x + y;
};
return f;
};
var g = add();
console.log(g(3));
add这个例子与第一个不同,我们现在返回的是函数的引用而不是值。然后,我们在函数调用时在函数作用域之外调用了该函数g(3)。这部分可能比较难理解。
让我们再回顾一下执行上下文,看看它是如何运作的。首先是全局执行上下文
接下来是add执行上下文
现在到了最有趣的部分。一旦add执行上下文完成执行,它将被弹出堆栈。
接下来是 g(3) 执行上下文。记住,该变量g包含函数f,因为它是 function 中返回的函数add。
所以g会返回x + y。我们正在运行g(3)所以的值y将是 3。
的值呢x?
好吧,如果我们四处寻找,我们将无法找到x。但我们记得在另一个已创建、执行并弹出的执行上下文中,它x被设置为。1
因此Javascript,如果一个函数在另一个函数(例如)内部创建g,那么g它将保留对封闭函数范围内变量的引用(在本例中)add。这意味着g仍然可以访问add包含变量的执行上下文的内存x。
基本上,add执行上下文已经结束,但g仍然允许访问仍在执行上下文内存中的执行上下文的变量add。
尽管它不再位于执行堆栈中,我们的函数g仍然可以沿着作用域链向上爬并找到它。x
g's执行上下文有closed in x一个 ,即使x's执行上下文消失了,它仍然是一个外部变量。所以我们的函数g是一个closure。
像函数这样的闭包g在内部存储对外部变量的引用。
我们有全局执行上下文范围。我们将拥有add和g变量以及它们的执行上下文。
行var g = add();完成后,添加执行上下文将从堆栈中弹出。(由于这个原因,它被阴影化了)
然后我们创建并执行执行上下文。即使执行上下文不再位于堆栈中,g它仍然可以引用外部变量。xx's
希望你通过本文对闭包有了一定的了解。如果你仍然感到困惑,请阅读以下参考资料。
这是我用来进一步理解这个主题的主要参考资料
执行上下文的终极指南
后端开发教程 - Java、Spring Boot 实战 - msg200.com










