前言
说到js闭包,早已不是什么新鲜事。
几乎是前端面试时必问的一道题,到如今已是烂大街的存在,但不可否认的是,仍然有一些人没有搞懂,只知其然不知其所以然,那么我们今天就好好的捋一捋。
从作用域说起
说的通俗一点,作用域就是:生效的区域。比如说,我们的身份证只在国内生效,出国就得用护照了。
1. JS 局部作用域(只在当前函数生效,函数外部无法访问)
2. JS 全局作用域(在整个Script标签内生效,函数内可以访问)
3. 从浏览器底层谈本质区别
可以看到:1. a变量在Script里,这意味着就是整个script标签内都可以使用。
2. b变量在Local里,译为局部,只能在方法内使用。
一图看懂作用域链
网上有大量讲作用域链的,但是大都模棱两可、讲不清楚,直接看上图,fn3()里定义了一个变量name2,同时包含了一个方法fn4()。
最后打印出来的却不是“木子”,而是“惠子”,如果把fn4()里面的name2注释掉掉,那么打印出来的是“木子”,不会报错。
所以我们得出来的结论就是:作用域链是由函数作用域组成的一个链条。
查找规则:根据函数作用域,一级一级往上查找,如果找到了就停止,输出或执行对应操作,如果找到全局作用域都没找到,报错(就近原则)。
作用域是分层的:内层作用域可以访问外层作用域的变量,反之则不行。
闭包
以一段代码为例:
当执行到return innerBar的位置时:
根据词法作用域的规则,内部函数getName和setName总是可以访问它们的外部函数 foo中的变量。
foo函数执行完成之后,其执行上下文从栈顶弹出了,但是由于返回的setName和getName方法中使用了foo函数内部的变量myName和test1,所以这两个变量依然保存在内存中,这两个变量的集合就叫做闭包。
闭包的经典应用(面试高频题)
1. 事件防抖
2. 私有方法与私有变量