Open CPPAlien opened 4 years ago
function add(num){
var sum = 5;
return sum + num;
}
js函数也是对象,对象拥有自己的属相。scope属性是每个函数都有的属相,这个属性只供js引擎使用。scope属性指向了一个链表(scopeChain),scopeChain保存了函数被创建的时的全局变量。
var sum = add(4)
函数被创建之后才能被执行。函数执行时,会创建一个运行时上下文(execution context),这个运行时上下文做两件事情:
1.运行时上下文会创建自己的scopeChain,然后将创建时的scopeChain中的globalObject拷贝过来
2.创建activation object(活动对象),活动对象的作用是记录函运行时的形参实参与定义的局部变量,然后将活动对象插入到运行时上下文的scopeChain中index为0的位置。每当函数执行过程中遇到变量时,先去搜索活动对象,也就是局部变量,然后再去搜索全局变量。
父函数执行的时,js引擎发现在函数的内部定义了函数,闭包函数也是函数,也需要为闭包函数记录创建时的上下文,比较特殊的是,此时的父函数处于执行期,父函数的执行期上下文还没有被销毁,刚好,闭包函数就直接引用了父函数的执行器上下文。
根据这个过程,我们可以解释为什么闭包函数可以访问自身的参数与局部变量,父函数的环境以及全局变量。闭包函数遇到一个变量的时候,会从上到下由内而外的搜索变量,因此,尽量将变量定义成局部变量,定义成局部变量可以提高访问速度,局部变量会被gc及时的释放,不会长期的占用内存。闭包能够访问反函数是因为闭包保存了父函数的环境变量的引用。没有内存,就没有闭包。
_val 在 useState 函数中首次赋值后,再也没被修改过,而内部函数无法去修改,因为闭包持有了 _val 的引用,更新 _val 并没有更新外部的foo,这其实不是一个闭包问题,而是 javascript 的引用复制问题;类似