文 / 景朝霞
来源公号 / 朝霞的光影笔记
ID / zhaoxiajingjing
图 / 自己画
❥❥❥❥点个赞,让我知道你来过~❥❥❥❥
前情提要:
0 / 看图说话
var n = 1;
function fn(){
var n = 2;
function f(){
n--;
console.log(n);
}
f();
return f;
}
var x = fn();
x();
console.log(n);
△ 画简版的,不用的会出栈销毁
创建函数
- 开辟一个堆内存
- 把函数体中的代码以字符串格式存到堆内存中
- 把堆内存的地址赋值给函数名/变量名
-
函数在哪创建的,在执行时需要查找的上级作用域就是谁。即:
FN[scope]:VO(G) F[scope]:AO(FN)
函数执行
- 开一个全新的栈内存:执行上下文EC(xx),会形成一个全新的私有作用域AO(xx)
- 形参赋值,变量提升(形参和在私有作用域中声明的变量:私有变量)
- 代码执行,把堆内存的代码字符串一行行拿出来运行
-
遇到变量:作用域链查找机制,找到它。
- 看它是否为自己当前执行上下文/私有作用域下的私有变量
- 是私有的,拿来用即可
- 不是自己私有的,沿着
scopeChain
作用域链向上级作用域查找。 - 上级作用域,如果有该变量,拿来用;如果没有该变量,再沿着作用域链向上级作用域查找
- 一直找到全局作用域为止
- <u>私有变量和外界的变量没有必然关系,可以理解为被私有栈内存保护起来了,这种机制就是
闭包保护机制
</u>
其中,EC(FN)
执行上下文在执行完后,返回了一个小函数f,外面的x接收了小函数f的地址。那么,EC(FN)
执行上下文/私有作用域中有东西被外界占用了,所以不会被销毁。
1 / 闭包
来~再念一遍:
<u>函数执行会形成一个全新的私有作用域,保护里面的变量不受外界干扰,这种保护机制就称为闭包。</u>
但是,我们经常听到这样说的:
函数执行会形成一个私有作用域,而这个栈内存不销毁,这样里面的私有变量与外面的不冲突,并且能保存这些值,叫做闭包。
这种说法呢,只把不销毁而留下来的称为闭包。
但,我理解的是当它形成了就已经是闭包了,这两种说法都OK,看个人理解认为哪种都OK。
闭包有两个作用:保护、保存
- 保护:保护私有变量不让外界干扰,与外界没有必然联系
- 保存:形成一个不销毁的私有作用域,私有栈内存里面的东西会保存下来;以后它里面的东西还能被调用到
2 / 练习题
请画图理解:作用域链查找机制、闭包机制。像上图画简单的即可。
- 输出结果是?fn函数执行完后是否会销毁?
console.log(a, b);
var a = 12,
b = 12;
function fn(){
console.log(a, b);
var a = b = 13;
console.log(a, b);
}
fn();
console.log(a, b);
注意:
var a = 12,
b = 12;
// 等价于
var a = 12;
var b = 12;
var a = b = 1;
// 等价于
var a = 1;
b =1;
- 输出结果是什么?哪些执行完后不会销毁?为什么?
var i = 20;
function fn(){
i -= 2;
return function (n) {
console.log(++i-n):
};
}
var f = fn();
f(1);
f(2);
fn()(3);
fn()(4);
f(5);
console.log(i);
- 输出结果是?
var i = 0;
function A(){
var i = 10;
function x(){
console.log(x);
}
return x;
}
var y = A();
y();
function B(){
var i = 20;
y();
}
B();
3 / 预告
如何判断THIS?