面试网页前端后台技巧(CSS+HTML)Web前端之路

JS中的闭包

2017-08-02  本文已影响39人  Bennt

闭包是JS中的一个重要的概念,在模块封装,保存变量中有着重要的作用,掌握闭包在前端开发中占着非常重要的角色。在了解闭包之前我们需要了解一下JS的垃圾回收机制和作用域。

一、垃圾回收机制

我们知道前端开发中,JS中最好不要存在过多的全局变量,这样可以避免全局变量的污染,和在创建新的变量或者函数中存在冲突的情况。所以有时候我们可能会看到如下所示:

var a = 1;
var b = a;
var a = null;

即将全局中不再使用的变量赋值为null。那大家知道为什么赋值给null,为什么不赋值给undefined?

这个就牵涉到JS的垃圾回收机制了,JS中的垃圾回收机制将会每隔一段时间,按照一定的算法和规则,找出不再使用的变量对象,进行回收,提高页面的性能,而a = null正是让a失去赋值1的引用,此时a就变成不再使用的变量对象了,将会在下一次的垃圾回收中被销毁。

二、作用域

JS中存在两种作用域,全局作用域和函数作用域(第三种作用域eval因为我们平常很少用到,并且浪费计算机算力,所以我们很少使用,这里不做讨论)。

var a = 1;
function demo(){
    var b = 2;
    console.log(a);
}
demo(); //1
console.log(b);  //  b is not defined

上面函数存在两个作用域,一个是全局作用域window,一个是函数demo的作用域,按照规范是函数作用域可以访问全局变量,而全局变量是不能访问函数作用域的变量,所以在执行demo函数的时候,能够打印出1,而在打印b的时候会报错没有找到。

三、闭包
var a = 1;
function demo(){
    var b = 2;
    function c(){
        console.log(b);
    }
    a = c;
}
demo();
a();  //2

上面代码执行流程为先执行demo函数,在内存中创建函数function(){console.log(b)},变量c指向该函数,通过a=c,a也指向该函数,当demo函数执行完毕后,不再存在c变量,然后执行a(),由于a已经获得函数c的引用,所以执行结果过打印出2。

闭包经典例子:
点击li标签,打印当前标签的索引。

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var ul = document.getElementsByTagName("ul")[0];
    var i = 0;
    var lis = ul.getElementsByTagName("li");
    var len = lis.length;
    for(;i<len;i++){
        (function(j){
            lis[i].onclick = function (){
                console.log(j);
            }
        })(i)   
    }
</script>

为什么需要使用立即执行函数(function(){})()?

在执行for循环的过程中,点击事件并没有触发,相应的函数也不会执行。如果不使用闭包保存i的话,当我们在点击li标签的时候,此时for循环已经全部执行完毕,此时i=2,无论点击任何i标签将会打印同样的结果。

使用立即执行函数的目的就是将每次for循环的i值保存在当前函数中,这样我们在每一次的点击li标签的时候就能获取当前li的索引值了。

上一篇下一篇

猜你喜欢

热点阅读