在了解闭包之前,先了解作用域
一,作用域
简单来说就是变量和函数可以访问的范围,在es5中变量作用域一般分为全局作用域和局部作用域,这个主要依据是全局变量还是局部变量
情景1: <script> var global = 'global' function test () { var local = 'local' console.log(global) } test() // 返回global console.log (local) // 报错:Uncaught ReferenceError </script> 此处的global就是全局变量,在整个代码内都可以访问到这个变量;变量local就是局部变量,只在函数local内部能访问到,在外部无法访问
情景2: <script> var global = 'global' function test () { local = 'local' } test() console.log(local) // 返回 local </script> 此处的global和local都是全局变量,在整个代码内都可以访问到这两个变量
情景1和情景2的对比分析:
因为JavaScript作为一门弱类型语言,声明一个变量只需要var一个保留字,如果在函数中不使用var声明变量,该变量将提升为全局变量,这就是为什么情景2中返回的值是local
二,作用域链
JavaScript里面采用的是函数作用域,每一个函数都有一个作用域,也算是一条独立的作用域链。比较典型的就是函数里面嵌套函数
<script> var result = 'global' function test () { var result = 'local' function inner () { console.log(result) // 返回local } inner() } test () console.log(result) // 返回global </script>
以上三段作用域构成作用域链,作用域链的查找顺序:inner本函数-->上一层test函数-->window全局对象,当调用内部的inner方法的时候,里面没有声明变量result,但是可以访问外部函数test的变量,如果外部函数依然没有这个变量,就继续查找全局变量,直到找不到为止,如果找不到的话,就抛出 ReferenceError 错误。通过作用域链,子函数可以访问父函数的变量,但是父函数无法访问子函数里面的变量,闭包就可以解决这个问题。
三,闭包
简单的理解就是有权访问另一个函数作用域中的变量的函数。
闭包理解的误区: <script> function test() { var result = 'local' return result } var res = test() console.log(res) </script>
上面的这个是闭包函数么?答案显示是no!以上的函数确实是实现了外部可以访问函数内部的变量result,但是当函数调用完成之后,里面的变量result也就用完了被销毁了,即函数内的局部变量的生命周期仅存在于函数的声明周期内,函数被销毁,函数内的变量也自动被销毁,所以这个函数不是闭包函数
闭包函数的正解,如下:
<script> function test () { var result = 'local' function inner () { return result } return inner } var res = test() console.log(res()) // 返回local </script>
上面的这段代码不仅实现了外部可以访问函数test内的变量result,同时当函数调用完的时候,通过闭包引用的外层作用域内的变量依然存在,并且将一直存在,直到执行的闭包作用域被销毁
四,闭包的特点
1,可以读取函数内部的局部变量
2,局部变量的值可以存在内存中,可以反复使用,并且不存在全局变量的污染问题
3,占用更多的内存,不容易被释放
应用场景如下: <script> function count() { var num = 0 function inner () { return num+=1 } return inner } var result = count() console.log(result()) // 返回1 </script>