下层基础决定上层建筑基础篇3-闭包

174 阅读3分钟

下层基础决定上层建筑基础篇3-闭包

根据js词法作用域的规则,内部函数总是能访问外部函数中的变量,当通过调用一个外部函数返回的一个内部函数后,即使外部函数执行结束了,但是内部函数引用了外部函数中的变量也依旧需要被保存在内存中,我们把这些变量的集合叫做闭包

有点难以理解对不对,不要紧,跟我走,你会发现闭包也不过如此,小小闭包拿捏,在讲解闭包之前我们先来了解一下,调用栈。

调用栈

在 JavaScript 中,调用栈(Call Stack)是一种数据结构,用于管理函数的执行。它是一个后进先出(Last-In-First-Out,LIFO)的栈,遵循先进后出的原则。

当 JavaScript 代码执行时,会创建一个全局执行上下文,并将其压入调用栈的顶部。每当调用一个函数时,会为该函数创建一个新的执行上下文,并将其压入调用栈的顶部。当函数执行完毕后,其执行上下文会从调用栈中弹出,控制权返回给上一个执行上下文。

var a = 2;
function add(b,c){
    return b + c;
}
function addAll(b,c){//被调用时进栈
    var d = 10
    var result = add(b,c) //调用add函数,进栈
    return a + result + d;
}
console.log(addAll(3,6)) // 输出21

编译完成行成全局作用域

image.png

执行第10行

image.png

第10行调用addAll函数,而函数执行到第7行,调用add函数,执行完之后add函数出栈,addAll函数也执行完之后也将出栈

可以将栈看成一个木桶,后放进去的东西先拿出来。

image.png

作用域链

1.函数在执行前会发生预编译,会执行上下文对象
2.变量环境中有个一个内定的outer属性,用于指明函数的外层作用域是谁
3.outer 的指向是根据词法作用域来定

- js引擎在查找变量时会先在函数中查找,找不到会根据outer的指向去外层作用域中查找
层层往上,这种查找的关系链就称为 作用域链
function bar (){
console.log(a);
}

function foo (){
    var a = 100;
    bar();//打印200
}

var a = 200;
foo()

打印出200是不是很奇怪,bar(),函数在foo函数中执行,foo函数中a=100,为什么不是打印100呢?

这个涉及到作用域链的概念。

在每个作用域中都会存在一个“outer”,其作用是明确指示该函数的外层作用域具体是谁。依据图示来看,bar 函数和 foo 函数的外层作用域均为全局作用域。按照内部作用域能够访问外部作用域,而反之则不被允许的原则,bar 所打印的“a”实际上访问的是全局作用域中的值,因而会打印出 200。 1716882663863.png

闭包

根据js词法作用域的规则,内部函数总是能访问外部函数中的变量,当通过调用一个外部函数返回的一个内部函数后,即使外部函数执行结束了,但是内部函数引用了外部函数 中的变量也依旧需要被保存在内存中,我们把这些变量的集合叫做闭包

- 作用
    1.实现共有变量(企业的模块开发)
    2.做缓存
    3.封装模块,防止全局变量污染

- 缺点
    1.内存泄露

话不多说,上代码

function foo(){
    var name = "x"
    function bar(){
        console.log(count,age);
    }
    var count = 1;
    var age = 18;

    return bar;
}
var age =20;
const a = foo();

在图文中都有解释

image.png