JS闭包相关:理论和举例
需求:当点击li的时候弹出li在ul中所处的位置即索引值。
html代码:
<ul>
<li>001</li>
<li>002</li>
<li>003</li>
</ul>
js代码:
var aLi = document.getElementsByTagName('li');
for (var i = 0; i<aLi.length; i++) {
aLi[i].onclick = function() {
alert(i); //得到的全是3 !
}
}
闭包的理论
执行环境
每调用一个函数时(执行函数时),系统会为该函数创建一个封闭的局部的运行环境,即该函数的执行环境。
每个函数执行环境都有一个作用域链,
子函数的作用域链包括它的父函数的作用域链。
作用域、作用域链、调用对象
函数作用域分为词法作用域和动态作用域。(新技能get~)
词法作用域是函数定义时的作用域,即静态作用域。
动态作用域是函数调用执行时的作用域。
词法作用域说明的是:在函数结构的嵌套关系下,函数作用的范围。
动态作用域就是:通过把该调用对象加到作用域链的顶部来创建的,此时的[[scope]]除了具有定义时的作用域链,还具有了调用时创建的调用对象。换句话说,执行环境下的作用域等于该函数定义时就确定的作用域链加上该函数刚刚创建的调用对象,从而也形成了新的作用域链。 再看这里的作用域,其实是一个对象链,这些对象就是函数调用时创建的调用对象,以及他上面一层层的调用对象直到最上层的全局对象。
闭包
所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包就是嵌套在函数里面的内部函数,并且该内部函数可以访问外部函数中声明的所有局部变量、参数和其他内部函数。
当该内部函数在外部函数外被调用,就生成了闭包。
(实际上任何函数都是全局作用域的内部函数,都能访问全局变量,所以都是window的闭包)
垃圾回收机制:如果某个对象不再被引用,该对象将被回收。
function f(x) {
var a = 0;
a++; //1
x++; //x参数传入时为1, 现在为2
var inner = function() {
return a + x;
}
return inner; // 3
}
var test = f(1);
alert(test()); //3
解决第一个栗子
html:
<ul>
<li id="a1">aa</li>
<li id="a2">aa</li>
<li id="a3">aa</li>
</ul>
js:
var lis = document.getElementsByTagName('li');
for(var i=0; i<lis.length; i++){
lis[i].onclick = (function(anystr){
return function(){
alert(anystr);
}
// 如果把 return function(){..} 换成直接alert;
// 会导致匿名函数直接运行,未点击就alert了3次;
}(i));
}
jsfiddle.net/gallenhu/e85xgn5v/embedded
用这种思想实现自增长的ID
var GetId = (function() {
var id = 0;
return function() {
return id++;
}
})();
var newId1 = GetId();
var newId2 = GetId();
var newId3 = GetId();
var newId4 = GetId();
alert(newId4); //3
浙公网安备 33010602011771号