函数和闭包
函数是一等公民
函数是一等公民,意思是函数时非常重要的。
函数可以做为另一个函数的参数,也可以做为另一个函数的返回值来返回。
js中函数中仍然可以定义函数,实现函数嵌套。
闭包
闭包 :包含两部分,函数和自由变量。
严格来说就是函数内部访问了外部的自由变量,这就是一个闭包。
代码执行过程
//闭包
function foo() {
var name = 'wang';
var age = 13;
function baz() {
console.log(name);
console.log(age);
}
return baz;
}
var fn = foo();
fn();
1.在堆中创建go对象, 并且创建了执行上下文栈
2.在执行上下文栈中创建了全局执行上下文
全局执行上下文中先预解析代码,foo为函数,foo会保存foo函数的地址,fn为变量,初始值为undefined
3.开始执行foo函数前先解析foo函数
执行foo函数会创建foo函数执行上下文,当前的vo对应的函数AO,因此会创建AO对象,预解析foo函数中的变量,baz指向函数baz函数的内存地址
真的的执行foo函数
执行代码后,name:wang , age:13 ,return baz 最终全局执行上下文接受到foo的返回值并赋给了fn,因此fn保存了baz函数对象的地址
foo函数执行完毕
foo执行完毕以后,相应的函数执行上下文会被销毁,正常情况下foo的AO对象也应该销毁,但此事baz函数的父级作用域指向的是foo的AO对象,所以不会被销毁。
执行fn函数
执行fn函数实际上是执行baz函数。首相,同样是创建baz函数执行上下文,创建baz的AO对象,因为没有定义变量,所以baz的AO对象为空,然后直接执行代码,打印name和age。因为当前AO对象中没有name和age属性,所以会从他的父级AO对象中查找name和age,查找都父级AO(foo)对象的name和age后,打印出来。
执行完fn函数
执行完fn函数以后,创建的函数执行上下文和AO对象都会被销毁。但foo的AO对象,因为一直有baz函数的parent scope 指向他,所以一直不会被释放。所有可能会出现内存泄漏,当我们不在使用它的时候可以通过 fn=null 来释放闭包,放置内存泄漏.
AO中不使用的变量
闭包可以访问外层AO的变量,使得外层AO不会被销毁,但是外层AO中不使用的变量,按道理应该不被销毁,因为整个AO都不会被销毁,但v8引擎做了优化,不适用的变量会被销毁,防止了内存泄漏。
function foo() {
var name = 'wang';
var age = 12;
function baz() {
debugger //设置断点
console.log(name);
}
return baz;
}
var fn = foo();
fn();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lWwwEu1-1633009655698)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210920103048996.png)]
可以看出闭包Closure中只剩下name变量。
r fn = foo();
fn();
![在这里插入图片描述](https://img-blog.csdnimg.cn/85d0e019bfb7495189939f5e27fde781.png#pic_center)
可以看出闭包Closure中只剩下name变量。