闭包解析:新手小白也能轻松理解的JavaScript教程

闭包,JavaScript 中非常有用的一个特性,初接触它时你可能觉得它很神秘让人摸不着头脑,但是!!你不用望而却步!今天我将带你轻松get闭包原理,将它理解透彻。

在进入我们今天的主题闭包之前,我们先要确保自己知道与闭包息息相关的两个概念,那就是调用栈和作用域链

调用栈

在 JavaScript 中,调用栈是用来管理函数调用关系的一种数据结构。当代码执行到一个函数时,会将该函数的信息(如参数、局部变量)压入调用栈中;当函数执行完成后,会将其从调用栈中弹出。这种先进后出的数据结构使得 JavaScript 可以追踪函数的调用关系,确保代码的执行顺序和上下文的切换。

作用域链

在 JavaScript 中,每个函数都有自己的作用域,并且可以访问其外部作用域的变量。当代码在一个作用域中无法找到某个变量时,JavaScript 引擎会沿着作用域链向上查找,直至全局作用域。这种链状的查找关系就是作用域链。

如果你对这两个概念还不太清楚的话,请先移步 《JavaScript调用栈和作用域链指南:新手也能快速上手》将其弄懂,这对我们接下来要理解的闭包非常重要!!

闭包

话不多说,我们进入正题,先看以下代码:

javascript 复制代码
function foo(){
    var myName = '阿美'
    let test1 = 1
    const test2 = 2

    var innerBar = {
        getName:function(){
            console.log(test1);
            return myName
        },
        setName:function(newName){
            myName = newName
        }
    }
    return innerBar;
}
var bar = foo()
bar.setName('洋洋')
console.log(bar.getName);

我们定义了一个函数foo,在函数foo里,声明了myName,test1,test2和innerBar;在对象innerBar里,我们又写了getName和setName两个函数体;getName里面打印test1,并return出myName的值,setName里传入一个newName,会把newName的值赋给myName;函数foo最终返回innerbar。最后我们把函数foo调用返回的值赋给bar。

foo调用后返回的是什么呢?,是对象innerBar,此时被赋给bar,即bar = innerBar。

bar.setName('洋洋')执行后myName被重新赋值为洋洋,最后执行console.log(bar.getName)会有两个打印,第一个是getName里的输出test1,另外一个就是getName里return出的myName,结果是1和洋洋

把这段代码弄明白后,我们来看调用foo后的调用栈:

首先编译全局将全局执行上下文入栈,之后执行foo调用后将foo执行上下文入栈,再执行将各个变量的值赋给它们,最后return出innerBar。当整个foo调用执行完成后,foo执行上下文将会销毁出栈,不再占用调用栈的空间:

但是!!执行foo的调用并将返回值赋给bar之后,我们需要执行bar.setName('洋洋'),此时setName的执行上下文入栈,那么setName的outer是指向哪的呢?setName函数处于foo的作用域里,所以setName的outer指向foo:

setName要将newName的值赋给myName,而myName在foo的变量环境里,好,到这里问题就出来了,foo执行完了要销毁它的执行上下文,但是执行setName又需要用到myName,而setName的myName要顺着outer的指向去foo执行上下文里找,那么foo里面的myName就不能被销毁掉,因为它之后还会被用到。

代码最后一行也是一样,console.log(bar.getName),getName函数需要用到foo里的test1,那么test1也是不能被销毁的。

所以,当销毁foo执行上下文的时候,就会检索出来之后还会被用到的test1和myName,它们将不会被销毁而是遗留下来成为一个闭包:

现在,我们就可以解释闭包了:

在js中根据词法作用域的规则,内部作用域总是能够访问外部函数中的变量的,当通过调用一个外部函数,返回一个内部函数后,即使外部函数已经执行完毕,但是内部函数引用了的外部函数中的变量依然会保存在内存中,我们把这些变量的集合叫做闭包。

以刚刚的例子来说就是,我们调用foo函数的时候,会返回它函数体里面的innerBar,而innerBar里面是包含函数getName和setName的,当foo调用执行完毕后,由于getName和setName还引用了foo里的变量,所以被引用的变量还会保存在内存中,这些被引用的变量的集合就叫做闭包。

今天的知识,你学到了吗ヾ(✿゚▽゚)ノ

相关推荐
小七蒙恩18 分钟前
java 上传txt json等类型文件解析后返回给前端
java·前端·json
糕冷小美n1 小时前
jeecgbootvue3列表数据状态为数字时,手动赋值的三种方法
前端·javascript·vue.js
mqiqe1 小时前
Nginx 配置前端后端服务
运维·前端·nginx
小羊小羊,遇事不难2 小时前
Error: near “112136084“: syntax
java·服务器·前端
Domain-zhuo3 小时前
CSS实现一个自定义的滚动条
前端·javascript·css·vue.js·git·node.js
autumn8683 小时前
css的长度单位有那些?
前端·css
李贺梖梖3 小时前
CSS2笔记
前端
张丹 新叶之扉3 小时前
vue的整理
前端·javascript·vue.js
鱼大大博客3 小时前
选择Edge Scdn时应考虑哪些因素?
前端·edge·ddos
️○-3 小时前
安装Node.js和npm
前端·npm·node.js