摘要:说源头说起闭包的产生由于变量作用域链引起的由词法作用域导致。闭包其实就是个称呼,重要的是在这种场景下内部函数可以调用外部函数的变量,而这正是因为词法作用域链。当闭包产生,在局部函数未被释放之前,被引用外部函数的变量就无法被释放。
今天在面试的时候被问到闭包,本身个人感觉还是挺懂的,一时半会突然又懵逼不知道从何说起(WTF). 好吧那我接下来在重新记录下吧:
其他时效优质文章,欢迎查阅
专业名词解释:在计算机中,闭包指引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在。
局限自定义: 在Javascript 中子函数中使用了其父函数或者外层函数的变量等就产生了一个闭包。这时外层变量的值能被子函数使用且外层变量在子函数未销毁之前一直被分配不会被释放。
说源头说起:闭包的产生由于变量作用域链引起的(由词法作用域导致)。
在ES5及之前的语言规范中作用域分3种:
全局作用域
局部(函数作用域)
eval作用域。
[注意:没有块级作用域]
在函数中定义的变量,就属于局部作用域,且只对函数范围内其他表达式可见。
而函数内部又可以使用父函数中的变量这就是由于作用域链,当JavaScript查找与变量关联的值时,会遵循一个查找链。这个链是基于作用域的层次结构。 如下代码:
var a = "global variable"; ( function () { console.log(a); var fn = function () { var a = "local variable" console.log(a); } fn(); })() //输出 //global variable //local variable
我们在window全局对象下声明了变量a,随后调用了一个立即执行函数,其中向控制台直接打印变量a,由于立即执行函数没有声明局部变量a所以导致JavaScript向其作用域链继续查找接着就在window对象中找到a变量并打印出它的值"global variable"。接着这个立即执行函数声明了一个局部函数变量再调用它,在这个函数变量中首先声明了一个局部变量a然后在向控制台输出a得值。JavaScript在执行时由于在fn函数作用域内部查找到了变量a就直接使用变量a的值所以打印出了local variable。
值得注意的是:
这里其实有2个闭包环境一个是window对象和立即执行函数所创建的闭包;另一个是立即执行函数和其内部声明的函数变量fn创建的闭包。
闭包其实就是个称呼,重要的是在这种场景下内部函数可以调用外部函数的变量,而这正是因为词法作用域链。
当闭包产生,在局部函数未被释放之前,被引用外部函数的变量就无法被释放。
清楚作用域的含义了吗???
那么我们刚刚说的“词法“作用域又是什么。
其实词法就是指代环境:由于函数决定作用域,并且函数是一等公民可以直接用来参数传递等。那么作用域链是怎样来确定的呢: 下面的话背熟了:
作用域链是根据函数定义时候的位置确定的而不是在调用时。--这就是“词法”作用域
如果你还不懂闭包我TM。。。
最后我们来看看几个老生长谈的基本栗子:
[闭包的影响]对一些li绑定点击事件并打印其索引,对比2断代码不解释:
var liListlength = 3; for(var i=0;ili")[i]; ele.addEventListener("click",function(){ alert("index is :" + i); }) } var liListlength = 3; for(var i=0;i li")[i]; ele.addEventListener("click",(function(i){ return function(){ alert("index is :" + i); } })(i)) }
[闭包的妙用]模拟封装
我们可以运用闭包模拟模块的实现,即我们可以只暴露方法接口隐藏局部变量,具体如下:
var countMoudle = (function(){ var _count = 0; var plus = function(){ _count++; }; var minus = function(){ _count--; }; var print = function(){ console.log(_count); } return { plus: plus, minus: minus, print: print }; })(); countMoudle.print() //0 countMoudle.plus() countMoudle.print() //1 countMoudle.minus() countMoudle.print() //0
此时我们只暴露出了方法名而没有暴露出变量属性,这时要对变量的修改只有通过接口方法调用。
最后如有任何问题和建议欢迎发送至邮箱讨论:
编写不易,若您觉得对您有帮助,欢迎打赏
微信:
支付宝:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/95367.html
语法 for ([initialization]; [condition]; [final-expression]) { statement } initialization一个表达式 (包含赋值语句) 或者变量声明。典型地被用于初始化一个计数器。该表达式可以使用var或let关键字声明新的变量,使用var声明的变量不是该循环的局部变量,而是与for循环处在同样的作用域中。用let声明的...
摘要:委托上面的代码结合了构造函数和原型两种方式去创建对象,首先聊聊构造函数构造函数构造函数本质上还是函数,只不过为了区分将其首字母大写了而已。注意注释掉的代码是自动执行的,但这并不是构造函数独有的,每个函数在声明时都会自动生成。 首先看看下面两个1+1=2的问题: 问题一:为什么改变length的值,数组的内容会变化? var arr = [1]; arr.length = 3; aler...
摘要:声明的变量不得改变值,这意味着,一旦声明变量,就必须立即初始化,不能留到以后赋值。 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总 1.HTML HTML5新特性,语义化浏览器的标准模式和怪异模式xhtml和html的区别使用data-的好处meta标签canvasHTML废弃的标签IE6 bug,和一些定位写法css js放置位置和原因...
摘要:声明的变量不得改变值,这意味着,一旦声明变量,就必须立即初始化,不能留到以后赋值。 虽然今年没有换工作的打算 但为了跟上时代的脚步 还是忍不住整理了一份最新前端知识点 知识点汇总 1.HTML HTML5新特性,语义化浏览器的标准模式和怪异模式xhtml和html的区别使用data-的好处meta标签canvasHTML废弃的标签IE6 bug,和一些定位写法css js放置位置和原因...
阅读 2511·2021-07-26 23:38
阅读 3415·2019-08-30 13:10
阅读 2291·2019-08-29 18:33
阅读 2293·2019-08-29 16:12
阅读 962·2019-08-29 10:59
阅读 1784·2019-08-26 17:40
阅读 746·2019-08-26 11:59
阅读 794·2019-08-26 11:41