javascript_function(闭包Closure)

javascript闭包(Closure)

所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(一般是一个函数),于是这些变量也是该表达式的一部分。javascript

上面是官方的解释,但这解释只会让人头晕。要理解闭包,首先理解两点:变量的做用域以及做用域链,这两个在前面都已经介绍过了,而且举了简单了列子,来回顾一下:java

var color = "blue";  
function changeColor(){     
    var anotherColor = "red";  
    function swapColors(){         
        var tempColor = anotherColor;         
        anotherColor = color;         
        color = tempColor; 
        //在 swapColors函数里面能够访问tempColor,anotherColor和color          
    } 
    //在这里能够访问anotherColor和color,但不能访问tempColor 
    swapColors(); 
}  

上面的代码,咱们以前用来讲明做用域链,也就是变量从里往外找变量,这一简单的概念。可是,如今反过来,若是,咱们须要在一个外部执行环境里面,访问内部执行环境的变量怎么办呢?闭包

function f1(){
    var n=999;
    function f2(){
        alert(n); // 999
    }
    //f2();
}

上面的代码很简单,咱们在f1里面去调用f2()固然能够弹出n的值999,可是若是咱们在外部全局执行环境里面还要得到n的值,这又该怎么办?这就是刚刚的提问,外部的执行环境要求访问内部执行环境的值。 从外往里访问,这里就能够经过闭包来实现这个效果,把上面的代码稍做修改:函数

function f1(){
    var n=999; //私有变量

    //在函数f1内定义另外的函数做为f1的方法函数
    function f2(){
        alert(n); //引用外层函数f1的临时变量n
    }
    return f2; //返回内部函数
}
//调用函数
var result=f1();
result(); // 999

当其中一个这样的内部函数在包含它们的外部函数以外被调用时,就会造成闭包(示例中,调用函数的时候,result实际调用的是f2函数,也就是说f1的一个内部函数f2在f1以外被调用,这时就建立了一个闭包)。spa

在看一个简单例子:code

function foo() {
    var a = 1;
    function geta() {
        a++;
        return a;
    }
    return geta
}

myfunc = foo()
myfunc() // return 2
myfunc() //return 3

上面只是一个说明闭包的例子,在实际应用中并不常见。下面咱们来看看实际应用中会遇到闭包的状况blog

状况一 界面上有一组a标签,分别点击,但愿点击不一样的a标签弹出不一样的结果,代码以下:ip

<ul>
    <li><a href="#">第0个连接</a></li>
    <li><a href="#">第1个连接</a></li>
    <li><a href="#">第2个连接</a></li>
    <li><a href="#">第3个连接</a></li>
</ul>    

var as = document.getElementsByTagName("a");
for(var i=0;i<as.length;i++){
    as[i].onclick = function(){
        alert("你如今单击的是第" + i + "个连接");
    }
}

上面这段代码的估计你们都遇到过相似的,想要的效果和实际出现的效果不一致,原本想点击每个,弹出不一样的i的值,可是没想到最后弹出的i的值都是4。 这正是因为变量的做用域链影响形成的,由于在用户单击a标签的时候才会调用onclick指向的匿名函数。而调用时,须要获得变量i的值,js解析程序首 先会在匿名函数内部查找i,可是没有定义。因而往外找,在外部执行环境中找到变量i,可是这个i已经被循环到4了,由于for循环在页面初始化的时候已经 被执行了。因此匿名函数里面的i实际上取得的是外部做用域链中i的值。想要改正这个错误,其实就是把i的值传入到匿名函数值就好了。可是匿名函数又不能传 值。这个时候,咱们就能够用闭包。 先建立这样一个函数:内存

function closureTest(num){
    return function(){
        alert("你如今单击的是第" + num + "个连接")
    }
}

这个函数直接返回了一个匿名函数,以前讲过闭包,因此,当返回的这个函数在外部被接收的时候,外层函数closureTest里的变量num,就会被保存起来,因此,将以前循环的代码修改一下:作用域

for(var i=0;i<as.length;i++){
    as[i].onclick = closureTest(i);
}

循环里面onclick调用的函数closureTest,并传入了参数i,而closureTest返回了匿名函数,因此根据闭包的原理,传入的参数i,就被保存在了内存当中,外部访问的就是每次不同的值了。固然,你也能够直接写成下面这个样子:

for(var i=0;i<as.length;i++){
    as[i].onclick = (function(i){
        return function(){
            alert("你如今单击的是第" + i + "个连接")
        }
    })(i);
}

状况二 利用闭包巧妙地传递参数,好比,有这样的场景,点击标签,而后延迟弹出一句话,而而这句话,是用参数传递过去的。先看下面的代码:

<a href="#">点击我</a>

var link = document.getElementById("myLink");
link.onclick = function(){
    setTimeout(function(){
        alert("你点击了点击个人超连接!");
    },1000);
}

这段代码,就是点击1秒后,弹出"你点击了点击个人超连接!",固然这里是直接把话写在了function里面,若是这段话是从外面传过来的呢?好比有个方法

function someFunction(words){
    alert(words);
}
var link = document.getElementById("myLink");
link.onclick = function(){
    setTimeout(someFunction,1000);
};

这里的话,问题就来了。怎么往someFunction传递参数呢?这个也能够直接用闭包

function someFunction(words){
    return function(){
        alert(words);
    };
}
var link = document.getElementById("myLink");
link.onclick = function(){
    var saySomething = someFunction("你点击了点击个人超连接!");
    setTimeout(saySomething,1000);
};

在动态执行环境中,数据实时地发生变化,为了保持这些非持久型变量的值,咱们用闭包这种载体来存储这些动态数据。这就是闭包的做用。也就说遇到须要存储动态变化的数据或将被回收的数据时,咱们能够经过外面再包裹一层函数造成闭包来解决。

相关文章
相关标签/搜索