JS闭包详解

一。前言

今天看到jQuery框架中很多API都用到了闭包的概念,闭包就是内部函数调用外部函数的变量,闭包中的一部分,还有其他特性。

JavaScript核心:对象 原型链 构造函数 执行上下文栈 执行上下文 变量对象 活动对象 作用域链 闭包 This 总结

参考资料    http://blog.csdn.net/ymjring/article/details/38981391

二。概念

闭包其实很多语言都具备的特性,python...,JS闭包主要涉及了这几个特性,作用域链,内存回收机制,匿名函数。

1.作用域链

在JS中每个函数都用自己作用域链,什么事作用域链,简单而讲就是函数的执行环境,上下文,即就是内存空间。内存空间存放着函数的局部变量的信息。(在此可以提醒一下,如果大家对函数内部是怎么存放于内存中的话,可以去看看汇编。根据汇编指令进行记录出栈进栈。)

function myTest(){
	var a = 100;
	return function(){
		return a;
	} 
}
这个是我们前面讲过的例子。这myTest函数的作用域是什么,在JS中每个函数都有自己的作用域,但是链式是怎么来的?JS函数会把它的父函数的作用域作为本函数的上一级作用域,直到全局变量window为止,做样就成了作用域链。就以这个例子讲讲

在上面有2个函数,我们简称外层的为外部函数,里面的为内部函数。外部函数的作用域链就是(外部函数作用域----全局变量),内部函数的作用域链(内部函数作用域----外部函数作用域----全局变量)

在内部函数中因为没有申明变量a,那么就是自身的作用域链上没有变量a,那么它就会沿着作用域链找到了上一级作用域(外部函数的),在这个外部函数作用域中找到了a的申明。这就是为什么闭包能够调用外部函数申明的变量。

2..内存回收

由于内部函数引用了外部函数变量a的值,导致myTest函数在执行完后不能释放内存(因为内部函数用到了它的变量),这样不能释放的内存就会一直存放在内存中,直到浏览器刷新,或者结束进程。虽然这里浪费了少量的内存。但是给我们JSER却带来了大大的方便。

三。实例

function myTest(){
	var a = 100;
	console.log(a);
}
myTest();
输出:a
函数中我只是给了一个局部变量,然后打印出来。大家都知道,在函数刚开始运行的时候,解析引擎会给这个函数创建属于它自己的上下文(即内存空间),在函数执行完毕后,解析引擎会把分配的内存空间销毁。

假如有种情况下我想在myTest()运行完后,还可以调用myTest内部的a变量,那该怎么办?

所以这就来到我们JS中的闭包了,它的功能之一就是可以让局部变量在函数执行完成后仍然存在于内存中。

function myTest(){
	var a = 100;
	return function(){
		return a;
	} 
}

var b = myTest();
var c = b();
console.log( c );
JS中在函数内部在申明匿名函数,那么就称被申明的匿名函数为闭包,上面的 function(){ return a },就是闭包,它被复制给b,然后将a的值赋给c,这样外部就可以在myTest()函数执行完后,可以获取a的值。然后利用。

再来:

var result=[];
function foo(){
    var i= 0;
    for (;i<3;i=i+1){
        result[i]=function(){
            alert(i)
        }
    }
};
foo();
result[0](); 
result[1](); 
result[2](); 
如果刚接触JS的同学都会认为输出的是1,2,3。然而有经验的JSER一眼看出来是3,3,3。
为什么呢?上面讲过闭包内可以访问外部函数里的变量,但是要注意一点,这里可以访问的方式是引用,就是你只是能通过地址访问到它的值,然而很多指针指向这个地址,那么只用其中一个对其进行修改,那么其他访问它的值也会随着变化,最重要是因为“引用”,相信了解C的人应该很清楚。
那怎么才能让他输出1,2,3呢?
var result=[];
function foo(){
    var i= 0;
    for (;i<3;i=i+1){
        result[i]=(function(j){
            return function(){
                alert(j);
            };
        })(i);
    }
};
foo();
result[0](); // 0
result[1](); // 1
result[2](); // 2
这里我只是把返回闭包的地方做了一层包装,在JS中函数传递参数,如果参数是简单的数据类型的话,那么会复制一个副本作为参数,简单而讲就是实参传参方式。

而且上面采用了JS立即执行函数的语法,即把当前 i 的值copy一个副本作为参数传递进去,这样每次循环都是传递当即 i 的值,这样就得到了0,1,2。

四。总结

在jQuery框架中看到哪很多地方用到了闭包,Sizzle解析器,CSS的API,事件的API,等等。这也是我在学习jQuery发现的,所以今天下记录下来。






你可能感兴趣的:(JS)