您的位置:首页 > Web前端 > JavaScript

javascript闭包

2016-05-30 21:05 393 查看

浅谈闭包

 

想弄清闭包,我们首先得知道我们为啥要用到闭包呢,我们想要在一个函数内部取到函数外部的变量,或者调用函数外部的方法都是很容易的,因为javascript查找变量或方法都是逆着作用域链向上查找的,但是我们现在有了这样一个需求:我们想在函数外面取到函数内部一个临时变量的值,这样的需求使得我们违背了javascript的基本原则。而闭包恰好帮助我们解决了这个问题。

 

接下来我们看一个例子:

function setName(){
    var name="CSDN";
    function getName(){
        return name;
    }
}
 

getName函数是不是取到了setName函数内部的临时变量,这确实是的。

 

我们再看一个经典的错误例子:

我们想在数组的每项上绑定一个函数,希望他执行的时候能一次打印0,1,2,,,9;

但是发现,他只能打印10个10!

function consoles(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=function(){
            console.log(i);
        }
    }
    return arr;
}

var arr=consoles();
for(var j=0;j<10;j++){
    arr[j]();
}
 

 

 

 

 

我们稍微把代码改一下:

 

 

 

function consoles(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=(function(num){
            return function(){
                console.log(num);}
        })(i)
    }
    return arr;
}

var arr=consoles();
for(var j=0;j<10;j++){
    arr[j]();
}
 

我们使得一个匿名函数自执行,返回一个函数给数组各项,这样就行了。

弄懂这两个基本可以理解闭包了,在讲这两个例子之前咋们还得说一个例子做一个铺垫~~(不要嫌我啰嗦啦。。。)

 

function setName(){
    var name="CSDN";
    function getName(){
        return name;
    }
}
 

这就是文章开头写的那个例子,如果我们直接在setName外面调用getName肯定是得不到name值的,但是如果我们这样稍稍变化一下呢,

function setName(){
    var name="CSDN";
    return function (){
        alert(name);
    }
}
var get=setName();
get();
 

我们在setName内部返回一个函数,在函数外部用get变量接受,继续调用get函数,打印CSDN,这样为什么就行了呢?原因就是我们返回的函数可能会被再次调用,所以他用到的setName的局部变量不会在setName调用完毕之后就被gc回收,局部变量name会常驻内存,当我们再次调用get函数即setName返回的函数,就会弹出”CSDN”;

我们这时候再回头看一下那个经典例子:

function consoles(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=function(){
            console.log(i);
        }
    }
    return arr;
}

 

为什么我们循环执for(j=0;j<10;j++){

arr[j]();

}

会打印10 个10 呢?

我们在这个函数中返回的是一个数组,每个项都存着一个函数,这跟我们之前直接返回一个函数,再调用,是不是大同小异啊,我们返回的数组中的10个函数有可能会被再次调用,所以我们在consoles函数中定义的局部变量i,是不会在consoles执行完毕就被垃圾回收机制回收,在循环结束i的值为10,这个值会一直保存在内存中,当arr[j]()调用时就会寻找到这个i值,这样就会打印10个10,如果我们在内部循环结束重新给i赋值1,这样就会打印10 个1了,现在清楚点了吧~~

 

那为什么我们这样改一下就行了呢?

function consoles(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=(function(num){
            return function(){
                console.log(num);}
        })(i)
    }
    return arr;
}

var arr=consoles();
for(var j=0;j<10;j++){
    arr[j]();
}
 

我们使用匿名函数的自执行,把i值传入匿名函数内部,我们返回的是表达式!这个表达式当然能够接收到我们传入的i值即num;

 

闭包就是能够访问函数内部变量的函数,闭包有两个特点1、他能够访问函数内部的变量2、她能让函数内部的变量常驻内存

正是由于这样我们才可以访问函数的局部变量,当闭包执行的时候,包含他的函数的执行环境会加入到闭包的执行环境中去,这个才是关键。。。。闭包越多消耗的内存就越多,因为她要保存包围他的函数的执行环境,所以不用闭包就要手动释放,通知垃圾回收机制回收内存,以免造成内存泄露。

真正要搞明白闭包,还是要清楚作用域链和函数的执行环境~~打好基础很重要~这样理解起来就会轻松一点了~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 闭包