目录
1、举例子
2、什么是闭包?
3、闭包的优点
4、闭包的缺点以解决方法
5、闭包的两道经典题
1、举例子
最简单的两个闭包例子:
// 闭包1(function(a){console.log(a) // 1})(1)
// 闭包2function fn(){var a = 2return function(){console.log(a) // 2}}fn()()
2、什么是闭包?
闭包:可以访问另一个函数作用域变量的函数。由于javascript
的特性,外层的函数无法访问内部函数的变量;而内部函数可以访问外部函数的变量(即作用域链)
由于在 Javascript 语言中,只有函数内部的子函数才能读取该函数的局部变量,因此可以把闭包简单理解成 “定义在一个函数内部的函数”。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以在函数外部读取内部的变量,另一个就是让这些变量的值始终保持在内存中。
闭包:在局部作用域引用上层作用域(非全局)的变量
3、闭包的优点
隐藏变量以及防止变量被篡改和作用域的污染,从而实现封装
4、闭包的缺点以解决方法
函数执行完后,函数内的局部变量没有释放,占用内存时间变长,容易造成内存泄漏。
由于保留了作用域链,会增加内存的开销。因此需要注意内存的使用,并且防止内存泄露的问题。
解决方法:
让内部函数变成垃圾对象,赋值为null,及时释放,让浏览器回收闭包
// 闭包3function fn1() {var b1 = 1var c1 = 2// 这个函数就是个闭包,可以访问外层 a 函数的变量return function() {var d1 = 3return b1 + c1 + d1}}console.log(fn1()()) // 6console.log(b1, c1, d1) // b1 is not defined
var test = (function(a) {console.log('第二步执行', a) // 1this.a = areturn function(b) {console.log('调用后的第三步',b) // 4return this.a + b}})((function(a, b) {console.log('第一步执行', a, b) // 1,2return a})(1, 2))console.log(test(4)) // 5
5、闭包的两道经典题
题目一:
var name = "the window";var obj = {name : "myObject",// 属性getNameFunc:function(){// 方法return function(){return this.name;};}};alert(obj.getNameFunc()()); // 输出了 “the window”;
答案: 输出了全局 the window,为什么不是对象属性 myObject 呢?
解法:形成一个闭包环境,需要两个条件:函数嵌套,子函数引用父函数局部变量,但是上面的例子,我只看到了函数嵌套,但没看到子函数引用父函数局部变量,所以这个函数嵌套根本就产生不了闭包环境,所以他不是个闭包。
调用 alert(obj.getNameFunc()()),注意,他有两个 () () ,调用第一个 () 时,实际上就是执行了getNameFunc()这个函数,但这个函数又嵌套了 return function(){ return this. name },
所以执行第一个括号时,就是执行了 return function(){ return this. name },到执行第二个 () 时,才是真正执行到了第二个函数的内部了,也就是 return this.name 了,但由于这个函数方法,他不是个闭包环境,所以 this 指向了 window 了,也就是 var name = “the winodw” ;
题目二:
var name2 = "the window";var obj2 = { name2:"my name is a obj",getNameFunc2 :function fn1(){var that = this; return function(){return that.name2; };}}alert(obj2.getNameFunc2()()); // 输出 my name is a obj
这次是输出的是 对象内的属性了,因为这次的才是真正的闭包环境,有函数嵌套,有父函数变量给子函数引用,形成依赖关系,产生闭包环境。
父函数明确定义了局部变量,var that = this;然后这个 that 呢,他又被子函数所引用,当 alert(obj2.getNameFunc()()) 执行时,就是执行子函数内部的 return that.name,
先在自身查找有没有 that.name,没有就返回上一层父函数,找到了 var that = this 了,这个就是闭包的环境。当然,两个函数执行域内都没有这个变量属性时,再往上一层,
也就是obj2对象内的属性,有个 name,终于在对象的执行域找到了,那就输出了 对象name的属性值。