下层基础决定上层建筑基础篇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
编译完成行成全局作用域
执行第10行
第10行调用addAll函数,而函数执行到第7行,调用add函数,执行完之后add函数出栈,addAll函数也执行完之后也将出栈
可以将栈看成一个木桶,后放进去的东西先拿出来。
作用域链
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。
闭包
根据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();
在图文中都有解释