这是我参与8月更文挑战的第10天,活动详情查看8月更文挑战
前言
闭包这个概念是前端工程师必须要深刻理解的,但是网上确实有一些文章会让初学者觉得晦涩难懂,网上关于"闭包"的文章数不胜数,而且文章质量良莠不齐。
本文面向初级的程序员,聊一聊我对闭包的理解,通过实例一步一步,带你理解闭包。
什么是闭包?
我们先来看看权威资料怎么说的:
JavaScript 高级程序设计(第 4 版)
闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
MDN 对闭包的定义为:
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
一般来说,小白看了上面关于闭包的定义,一脸懵逼,这到底是啥意思?
这里,先抛出方应杭老师总结的闭包,后面会围绕“函数”和“函数内部能访问到的变量”,进行讲解
「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
通过例子理解闭包
先来看下例子:
function init() {
var name = "Mozilla";
function sayName() {
console.log(name); // "Mozilla"
}
sayName();
}
init();
运行上面代码,输出结果是 "Mozilla"。
我们想想,为什么输出结果是 "Mozilla"?我们一步一步分析下。
上面这个例子中,有 init 的函数作用域、sayName 的函数作用域和全局作用域。它们的关系示意如下:
当 sayName 函数被调用的时候,执行 console.log(name);,我们试图在 sayName 这个函数里面访问变量 name 的时候,发现在当前函数作用域内并没有找到这个变量,因为 sayName 这个函数作用域没有对 name 这个变量声明,所以一开始肯定是找不到的。
要想找到 name,该怎么做?可以理解,这个时候,JS 引擎探出头去,去上层作用域(init) ,找到了 name,那么就可以直接拿来用了。
在这个查找过程中,层层递进的作用域,就形成了一条作用域链,作用域链关系展示如下:
再回到这句话,「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
函数 sayName 和 init 函数里面的变量 name,就是一个闭包,也就是下图的 Closures。
从上图,我们可以了解到闭包处于一个函数和变量作用域之间的灰色地带。
上面的例子,可以很好的反驳,“函数嵌套了函数,然后返回一个函数”的闭包的解释。
在 JS 中,闭包存在的意义,就是让我们可以间接访问函数内部的变量。
参考
文中如有错误,欢迎在评论区指正,如果这篇文章帮助到了你或者喜欢,欢迎点赞和关注。