JavaScript 闭包
作用域
在Js
中,所有的名字(变量/常量/函数/类)都有一个作用范围,这被称之为作用域。
全局作用域
全局作用域即是在全局下定义的名字作用范围,在Js
中全局作用域中的名字全局有效,在任何作用域中都能进行访问。
生命周期:页面打开则产生,页面完毕时销毁
数量:最多只有一个
局部作用域
局部作用域通常是指在函数中定义的名字作用范围,局部有效,外部不能访问。
生命周期:对于函数的局部作用域来说,函数调用时存活,调用完毕则销毁,也就是说每次调用函数都会新增一个局部作用域。函数执行完毕后该作用域将不复存在。
数量:可以有多个局部作用域
块级作用域
块级作用域的范围小了很多,它只包含在{}
中由let/const
定义的名字的作用范围,也是局部有效,外部不能访问。
生命周期:块级作用域是可以有多个的,生命周期为当执行块级作用域中代码块时块级作用域存活,执行完毕后块级作用域销毁。
数量:可以有多个块级作用域
名字查找顺序
先到自身的作用域中查找,如果没有再到定义自己作用域的作用域中进行查找。
<script>"use strict"; let username = "云崖"; let age = 18; function show() { let username = "Yunya"; // 如果这里注释掉下面的查找结果是云崖 let age = 16; console.log("show..."); (function () { console.log(username); // Yunya }()); } show(); </script>
块级作用域的封装
在之前没有块级作用域这一概念之前进行模块封装都是使用自执行函数利用它函数局部作用域的特性进行封装,但是现在有了let/const
块级作用域后我们又有了新的封装方式。
封装
{ let show = function () { console.log("执行了show功能"); } let test = function () { console.log("执行了test功能"); } window.module = { show, test }; };
调用
<script src="JavaScript.js"></script> <script>// 注意上面要引入模块 "use strict"; module.show(); module.test(); </script>
闭包
闭包其实非常简单,它是基于函数嵌套+作用域+函数参数进行实现的。
闭:一个封闭的函数,不能被外部直接调用,所以该函数肯定是在一个局部作用域或块级作用域中。
包:一个包裹闭函数的函数被称之为包函数。
我们一定要注意一件事,即局部作用域的销毁是在函数执行完后进行销毁,但是这个销毁时机是有讲究的。
如果我们将局部作用域中的一个名字返回出去,那么该局部作用域的销毁时机是什么呢?这个得看情况。
该名字指向的是一个值类型:立即销毁!值类型直接复制值就好了。
该名字指向的是一个引用类型:不销毁!引用类型可能会被引用,你把局部作用域销毁了那块内存地址就空了,引用类型还引用个毛线。
<script>"use strict"; function outer(){ let username = "云崖"; // 由于返回的是一个引用对象,故outer的作用域环境不会被销毁,如果销毁了内存地址清空就找不到这个 // 函数了,由于outer的作用域环境不会销毁那么username也将会存活。 return function(){ console.log(username); // 自己找不到,去上层找呗。然后找到了 云崖 } } let func = outer(); // func就是返回出来的匿名函数 func(); </script>
闭包注意事项
少用,少用。
不销毁局部作用域代表不销毁这一块的内存,因此每做一个闭包函数一旦调用就会多出一块跟随全局作用域销毁的局部作用域,如果调用多了这个闭包函数那就emmm....