JavaScript 中的闭包
闭包是很多新开发者似乎都难以理解的概念之一。我自己就是其中之一。在这篇文章中,我将尝试通过解决我最初学习闭包时忽略的一个问题:数据持久化,来让这个神秘的概念不再那么神秘。
MDN 对闭包的官方定义如下:“闭包是将函数与其周围状态(词法环境)的引用捆绑在一起(封装)而成的组合。换句话说,闭包允许你从内部函数访问外部函数的作用域。在 JavaScript 中,每次创建函数时,都会创建闭包,即在函数创建时。”
JS 中的闭包有三个主要特征:
- 一个函数必须返回另一个函数
- 内部函数可以访问外部函数的变量
- 外部函数的变量值被保留
让我们看一个闭包示例:
function parentFunc() {
var counter = 0;
function childFunc(){
let innerCounter = 0;
innerCounter++;
counter++;
console.log(counter, innerCounter);
}
return childFunc;
}
const myChild = parentFunc();
myChild();
在上面的代码片段中,我们有一个名为 的函数parentFunc()
,它返回其嵌套函数childFunc()
。parentFunc()
将var counter
设置为 0。childFunc()
将设置为 0,它将和var innerCounter
都递增,然后记录两者。我们将 设置为等于执行的。counter
innerCounter
const myChild
parentFunc()
上述代码的输出为:
1 1
很简单吧?
如果我们执行myChild()
多次会怎么样?
function parentFunc() {
var counter = 0;
function childFunc(){
let innerCounter = 0;
innerCounter++;
counter++;
console.log(counter, innerCounter);
}
return childFunc;
}
const myChild = parentFunc();
myChild();
myChild();
myChild();
现在的输出是:
1 1
2 1
3 1
在常规函数中,一旦执行完毕,数据就会被清除,不会保留任何数据。
然而,使用闭包时,内部函数会将外部函数的变量存储在其自己的特殊位置,我们可以将其想象成一个背包。外部函数执行后,其内部的数据会被清除,但内部函数会将这些数据存储在其背包中,方便其取用。需要注意的是,它只将来自 parentFunc() 的变量存储在背包中,其自身的变量innerCounter
会被视为常规函数,并在执行后被清除。
childFunc()
var counter
函数执行完毕后,该值将保持不变。这意味着,在第二次执行开始时var counter
,该值不会设置为 0,而是设置为 1;在第三次执行开始时,var counter
该值设置为 2。
当我们想要记住函数中的某些值时,使用闭包是一个很好的选择。
结论
JS 中的闭包有三个主要特征:
- 一个函数必须返回另一个函数
- 内部函数可以访问外部函数的变量
- 外部函数的变量值被保留
闭包是 JavaScript 中比较微妙的概念,乍一看可能有点难懂。但一旦你深入理解了闭包的三个主要特性,你就会发现它们其实并没有那么有争议。
希望这篇文章能帮助您更好地理解 JavaScript 中闭包的概念!
文章来源:https://dev.to/mariaverse/closures-in-javascript-3289