JavaScript 闭包那些事
闭包的产生由于变量作用域链引起的(由词法作用域导致)。
从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创建的闭包。闭包其实就是个称呼,重要的是在这种场景下内部函数可以调用外部函数的变量,而这正是因为词法作用域链。
当闭包产生,在局部函数未被释放之前,被引用外部函数的变量就无法被释放。
清楚作用域的含义了吗???
那么我们刚刚说的“词法“作用域又是什么。 其实词法就是指代环境:由于函数决定作用域,并且函数是一等公民可以直接用来参数传递等。那么作用域链是怎样来确定的呢: 下面的话背熟了:作用域链是根据函数定义时候的位置确定的而不是在调用时。--这就是“词法”作用域
[闭包的影响]对一些li绑定点击事件并打印其索引,对比2断代码不解释:
var liListlength = 3; for(var i=0;i<liListlength;i++){ var ele=document.querySelectorAll(".test > li")[i]; ele.addEventListener("click",function(){ alert("index is :" + i); }) } var liListlength = 3; for(var i=0;i<liListlength;i++){ var ele=document.querySelectorAll(".test > 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
编辑:--ns868