js闭包-个人浅理解

来源:互联网 发布:毛利寿三郎 越知月光 编辑:程序博客网 时间:2024/06/05 06:20
闭包是很多语言都具备的特性,,几乎每次面试必问的问题,在js中,闭包主要涉及到js的几个其他的特性:作用域链,垃圾(内存)回收机制,函数嵌套,等等.要理解闭包,可以先理解下作用域.
1.作用域链
先理解两个概念:
[1]全局变量和它的作用域
     全局变量是指在程序开头的说明部分定义和说明的量。它的作用域分为两种情况: 
(1)在全局变量和局部变量不同名时,其作用域是整个程序。 
(2)在全局变量和局部变量同名时,全局变量的作用域不包含同名局部变量的作用域。 
[2]局部变量和它的作用域 
  凡是在子程序内部使用的变量,必须在子程序中加入说明。这种在子程序内部说明的变量称为局部变量。局部变量的作用域是其所在的子程序。形式参数也只能在子程序中有效。因此也属于局部变量。局部变量的作用域分为两种情况: 
(1)当外层过程序的局部变量名和嵌套过程中的局部变量不同名时,外层过程的局部变量作用域包含嵌套过琛。
(2)当外层过程的局部变量名和嵌套过程内的局部变量名同名时,外层局部变量名的作用域不包含此过程。
[3]作用域链
作用域链就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的局部作用域放在最前面,把自身的父级函数中的作用域放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止. 
js中查询变量的次序:查询位置所在子函数的作用域-父级函数的作用域-高一级函数的作用域.....-全局作用域.
2.闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行.
简单理解:可以说js中变量查询要想从父级作用域到次级作用域,可以调用次级函数访问到次级函数的内部变量.
就像公司的领导(全局作用域)不知道内部每个部门(次级函数)的员工信息(次级作用域),他要想找到某个员工(某个变量),可以去问每个员工所在部门的负责人(调用次级函数)就可以找到那个员工.
可能这样说比较不清楚,可以看一个例子说明.
var a=1;
function foo() {                      
var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
console.log(a);//1
foo();
这段代码中,a=1是一个全局变量,console.log(a)是打印的一个全局变量;而我们想访问函数foo()内部的a;我们需要调用foo函数,访问到内部的a=2.这就是闭包-函数作用域外面调用此函数可以继续访问该函数内部的作用域.
下面看一个经常理解出错误的例子:
for (var i=1; i<=5; i++) {
console.log( i );//1,2,3,4,5
setTimeout( function timer() {
console.log( i );//6,6,6,6,6
}, i*1000 );
}
这段代码的结果你看明白了吗?实际上定时器执行的函数是在for循环全部完了之后再执行的.
for (var i=1; i<=5; i++) {
(function(){
var j=i;
setTimeout( function timer() {
console.log( j );//1,2,3,4,5
}, j*1000 );
})();
}
这段代码通过闭包解决了上个例子中的问题,在每次迭代中,用j来存储了每个i的值.
for (var i=1; i<=5; i++) {
(function(i) {
setTimeout( function timer() {
console.log( i ); //1,2,3,4,5
}, i*1000 );
})( i );
}
我们可以将每次的迭代的i作为参数传进函数内部.





0 0