闭包的简单认识
闭包的定义
-
一个函数和对其周围环境(词法环境)的引用绑定在一起(或者说函数被引用包围),这样的组合就是闭包。也就是说,闭包可以让你在一个内层函数中访问到其外层函数的作用域。在js中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
// 简单的闭包,在函数中return中返回一个函数并调用 function makeFunc(){ let name = "Tom"; return () => { alert(name); } } let myFunc = makeFunc(); myFunc();
let myFunc = makeFunc()
执行结束后,相应的函数执行上下文就从栈中弹出,一般情况下,其变量也会随之销毁,但是myFunc()
调用了muFunc
,即执行了function displayName(){alert(name);}
,这里的name
引用着makeFunc
里的变量name
,所以其变量并不会随着销毁,相当于封装了一个私有变量。 -
容易理解的闭包概念:闭包就是一个函数引用另一个函数内部的变量,因为变量被引用着,所以当另外一个函数执行结束,其相应的执行上下文弹出栈时,变量并不会被回收,因此可以用来封装一个私有变量。这既是优点也是缺点,不必要的闭包只会增加内存消耗,因为没有使用的变量并不会被及时回收。
-
更严谨的描述:
闭包是由函数以及声明该函数的词法环境组合而成的。该词法环境包含了这个闭包创建时作用域内的任何局部变量。
一些简单的问题
-
立即执行函数
// 立即执行函数 let add = (function (){ let count = 0; return () =>{ return count += 1; } })(); console.log(add()); //1 console.log(add()); //2 console.log(add()); //3 add =null; add();
-
定时器打印问题
// 定时器打印问题 for(var i = 0;i < 5;i ++){ setTimeout(() => { console.log(i); }, 1000); }
上面代码中,变量i是var命令声明二点,在全局范围内都有效,所以全局只有一个变量i。每一轮循环,变量i的值都会覆盖上一轮的值。上面定时器函数的回调会在循环结束时才执行。这个循环的结束条件是i不再<5,条件首次成立时i的值是5,因此,输出显示的是循环结束时i的最终值,因此每次输出一个5来。我们可以利用闭包来解决上面的问题。
//利用闭包解决上面的问题 for(var i = 0;i < 5;i ++){ (function(j){ setTimeout(() => { console.log(j) }, j*1000); })(i) }
闭包的作用、
- 保护函数的私有变量不受外部的干扰,形成不销毁的栈内存。
- 保存,把一些函数内的值保存下来,闭包可以实现方法和属性的私有化。