那句话大概意思说,只要是在函数内部定义的变量,在整个函数内都是有效的。所以结果也就不难理解了。在回过头看我们的那个问题,你理解了吗?
作用链还有以下定义:
1、作用链是有一个全局对象组成。
2、在不包含嵌套的函数体内,作用链上有两个对象,第一个定义了函数参数和局部变量的对象,第二个是全局对象。
3、在一个嵌套的函数体内,作用链上至少包含三个对象。
当定以一个函数的时候,就会保存一个作用域链。
当调用这个函数时,它就会创建一个新的对象来存储它的局部变量,并将这个对象添加到保存的作用链上。同时创建一个新的更长的表示函数调用的作用链。
对于嵌套的函数,当调用外部函数时,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用链都是不同的。内部函数在每次定义的时候都有微妙的差别,每次调用的外部函数时,内部函数的代码都是相同的,而且关联的代码的作用域也是不同的。
闭包
搞了这么久终于要讲了,但是再将之前我们在来分析下作用域。
<script> var nameg="global" var g = function f() { console.log(name); function demo() { console.log("demo="+name); } var name = ""; function demo() { var name = ""; console.log("demo=" + name); } function demo() { console.log("demo=" + nameg); } demo(); demo(); demo(); }; g(); </script>
我们按照作用链来分析:
调用demo0, demo0()->查找name,未找到->f()查找,返回
调用demo1,demo1()->查找name,找到,返回
调用demo2,demo2()->查找nameg,未找到->f()查找nameg,未找到->window查找nameg找到,返回。
看这个例子:
<script> function f() { var count = ; return { counter:function() { return count++; },reset: function() { return count = ; } } } var d = f(); var c = f(); console.log("d第一次调用:"+ d.counter());// console.log("c第一次调用:"+ c.counter());// 互不影响 console.log("d第一次调用:"+ d.reset());// console.log("c第二次调调用"+ c.counter());// </script>
这个例子上大家可以看到,我做了一个计数和置零的操作。
创建了两个f的对象实例d c,各有自己的作用域链,所以其值互不影响。当c第二次调用时,count值被保存了,因为c对象并未被销毁。明白这个例子后,后面的例子才比较好懂。
这个过程,大家应该十分明了了。那么现在我们来看闭包问题。我设置四个按钮,点击每个按钮就返回响应的名字。
<body> <script> function btnInit() { for(var i=;i<;i++) { var btn = document.getElementById("btn" + i); btn.addEventListener("click",function() { alert("btn" + i); }); } } window.onload= btnInit; </script> <div> <button>Btn</button> <button>Btn</button> <button>Btn</button> <button>Btn</button> </div> </body>
点击运行,结果却是都是btn5;
我们用刚才的分析在坐下,首先要调用匿名函数->查找i,未找到->btnInit(),找到i在for循环中。找到。我们知道只有函数调用结束才释放,for中的i总是可见的,所以保留了最后的i值。那么如何解决呢。
解决i值在函数中不是总是可见的,那么我们就要使用函数的嵌套了,然后把i值传进去。
function btnInit() { for(var i=;i<;i++) { (function (data_i) { var btn = document.getElementById("btn" + data_i); btn.addEventListener("click", function () { alert("btn" + data_i); }); }(i)); } }
看修改后的代码,首先执行第一次for,创建了一个对象,我们首先是执行匿名函数->data_i,未找到->function(data_i)找到,然后再次执行for有创建一个对象,闭包规则说的互不影响。所以能得出正确的结果。