闭包
一、作用域
-
JavaScript作用域:分为全局作用域、局部作用域。变量在某个范围内起作用和效果,目的是为了提高程序的可靠性和减少命名冲突。
-
变量的作用域:根据作用域的不同我们变量分为全局变量和局部变量。两种变量其主要区别是函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。
-
作用域链:
-
根据内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为作用域链。
-
只要是代码,就至少有一个作用域。
-
写在函数内部的局部作用域。
-
如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
-
1.全局变量
- 概念:在全局作用域下的变量,在全局下都可以使用。
- 如果在函数内部没有声明直接赋值的变量也属于全局变量。
- 只有浏览器关闭的时,全局变量才会销毁,比较占内存资源。
- 全局作用域:整个script标签中,或者是一个单独的js文件。
2.局部变量
- 在局部作用域下变量,即在函数内部的变量就是局部变量,只能在函数内部使用。
- 函数的形参也可以看做是局部变量。
- 当我们程序执行完毕时,局部变量就会销毁,比较节约内存资源。
- 局部作用域(函数作用域):在函数内部就是局部作用域,这个代码的名字(变量)只在函数内部起作用和效果。
二、理解闭包
1.闭包的概念
- 闭包是指有权访问另外一个函数作用域中的局部变量的函数。声明在一个函数中的函数,叫做闭包函数。而且内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
2.闭包的特点
- 让外部访问函数内部变量成为可能。
- 局部变量会常驻在内存中。
- 可以避免使用全局变量,防止全局变量污染。
- 会造成内存泄漏(有一块内存空间被长期占用,而不被释放)。
3.闭包的分析
- 闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,并且互不干扰。
- 闭包会发生内存泄漏,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。
- 但当外部函数运行结束甚至销毁时,局部的变量key=value,尽管key被垃圾回收机制给回收了,但是value仍不会被回收,会变成一个自由变量留下引用的指针。
4.闭包的实现案例
-
利用闭包的方式,输出点击项的索引值
<ul class="closure"> <li>苹果</li> <li>香蕉</li> <li>橘子</li> <li>西瓜</li> </ul> <script> // 获取所有的li元素 let lis = document.querySelectorAll('.closure li') // 利用for循环创建了4个立即执行函数 for (let i = 0; i < lis.length; i++) { (function (i) { lis[i].addEventListener('click', function () { console.log(i) }) })(i) } </script>
-
利用闭包的方式,3秒钟之后,打印所有li元素的内容
<ul class="closure"> <li>苹果</li> <li>香蕉</li> <li>橘子</li> <li>西瓜</li> </ul> <script> // 获取所有的li元素 let lis = document.querySelectorAll('.closure li') for (let i = 0; i < lis.length; i++) { (function (i) { setTimeout(() => { console.log(lis[i].innerHTML) }, 3000) })(i) } </script>