1、闭包就是指有权访问另一个函数作用域中的变量的函数,这句话有两个点,1闭包是函数,2作用域。
有了这两个条件我们能联想到的就是js的执行环境。函数的执行环境依赖于变量作用域,在js中这个作用域是函数定义时决定的,而不取决于调用时。通过如下案例来解释:
var a = ‘hello‘ //全局变量
function fun() {
var a = ‘world‘ //局部变量
function fn() {
return a
}
return fn()
}
console.log(fun()) //world
var a = ‘hello‘
function fun() {
var a = ‘world‘
function fn() {
return a
}
return fn
}
console.log(fun()()) //world
//函数fun返回值fn,fn执行过程中取得a的值为fn定义时的值,而并非取得全局变量
如果按照正常的说法,函数在执行完毕后,其内部相关的作用域链会被回收,而闭包恰巧就是钻了空子,使得函数中的作用域链再次其内部的变量不被销毁,所以在有些场合,尤其是循环操作DOM的过程中,过度的使用闭包,可能会造成内存泄漏。
2、通过上面的案例,我们认识到,闭包就相当于一个块,这个块里包含所定义时的作用域。现在尝试用闭包写一个计数器
function sum() {
var a = 3 //私有变量
return {
add: function(k) {
return a + k
},
del: function(k) {
return k - a
}
}
}
var i = sum()
var j = sum()
console.log(i.add(1)) //4
console.log(j.add(3)) //6
console.log(i.del(9)) //6
console.log(j.del(6)) //3
我们开始定义了个sum函数,返回两个add和del函数形成闭包,在对其两个函数进行分别操作时,发现i,j变量分别控制的是不同的两个结果,这就表明,两个方法 都可以访问私有变量 a 而每次调用add都回创建一个新的作用域链和一个新的私有变量,可以多次重复使用,不会影响到彼此。但是两者都仅仅局限sum函数创建下,现在对其进行改造写法:如下:
(function(w) {
var a = 3
this.add = function(k) {
return a + k
}
this.del = function(k) {
return k - a
}
}(window))
console.log(add(1)) //4
console.log(add(3)) //6
console.log(del(9)) //6
console.log(del(6)) //3
结果和上述一致,区别在于被调用的对象有不同,我们通过一个匿名函数来把我们要执行的函数添加到window对象上,来达到全局变量的目的, 我们可以这样理解,一个匿名函数就相当于一个大的作用域,而内部的变量每次都只能在内部调用,其他外界函数是访问不到的,这样就保证了一个独立的作用域链.
3、总结闭包的优缺点
* 优点 1、使用闭包可以通过外部函数访问内部的函数值,提升作用域,便于链式调用
* 优点 2、内部的变量可以多次重复使用,不会造成全局的变量污染。
* 优点 3、全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,有效防止了
* 缺点 1、闭包创建的变量都被保存在内存中,内存消耗很大,处理不当,IE中容易造成内存泄漏。