掘金评论:本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放
任何闭包的使用场景都离不开这两点:
- 创建私有变量
- 延长变量的生命周期
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的
举个例子:
var data = [];for (var i = 0; i < 3; i++) {data[i] = function () {console.log(i);};}data[0]();data[1]();data[2]();// 3 3 3
当执行到data0的时候,上面的for循环已经执行完成了,i是全局变量这个时候打印的i已经是3了。
data[0]其实就是一个打印 i 的函数
for (var i = 0; i < 3; i++) {}console.log(i) // 3
再看看闭包版本
var data = [];for (var i = 0; i < 3; i++) {data[i] = (function (i) {return function(){console.log(i);}})(i);}data[0]();data[1]();data[2]();// 1 2 3
下面是个人理解
var data = [];for (var i = 0; i < 3; i++) {data[i] = (function (i) {return function(){console.log(i);}})(i);}data[0]();data[1]();data[2]();// 这时候data[0]就相当于(function (i) {// 这里的i是0return function(){console.log(i);}})(0)// 实际上这里应该有两个i 一个是for循环的时候 用var 声明的全局变量i这个i的值等于3,也就是第一段函数的例子当函数执行console.log(i);只有全局作用域找到了全局变量i,这个i等于3 所以输出的值是3// 第二个i是自执行函数内部的i,在data[0]的时候因为当时循环传的参数是0,所以自执行函数内部的i也是0,当执行console.log(i);时向上查找i先遇到的是自执行函数的函数作用域,这里的i等于0,就直接打印了0,当然在这个时候外部全局变量的i也是3,只是因为被函数作用域的i截胡了所以没有打印3// data[1] data[2] 同理
