JavaScript闭包原理与用法实例分析

1、与闭包有关的两个概念:

1) 变量的作用域

不带有关键字var的变量会成为全局变量;

在函数中使用关键字var声明的变量是局部变量。

局部变量只有在函数内部才能访问到,在函数外面是访问不到的。但在函数内部可以通过作用域链一直向上搜索直到全局对象,也就是说,函数内部可以访问函数外部的变量。

2) 变量的生存周期

对于全局变量,其生存周期是永久的,除非主动销毁这个全局变量;

而对于在函数内用关键字var声明的局部变量,当退出函数时,这些局部变量会随着函数调用结束而被销毁。

var func = function() { var i = 1; alert(i); // 输出:1 }; alert(i); // 报错:i is not defind.

例外情况:闭包

var func = function() { var i = 1; return function() { alert(i); i++; } }; var f1 = func(); f1(); // 输出:1 f1(); // 输出:2 var f2 = func(); f2(); // 输出:1 f2(); // 输出:2

2、从闭包的一个经典应用谈起

<div>0</div> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <script> var divs = document.getElementsByTagName("div"); for (var i = 0; i < divs.length; i++) { divs[i].onclick = function() { alert(i); }; } </script>

问题:无论单击哪个div,都会弹出5。

原因:onclick事件是异步触发的,当事件被触发时,for循环早已结束,此时变量i的值早已经是5。

解决:在闭包的帮助下,把每次循环的i值都封闭起来。当事件函数顺着作用域链从内到外查找变量i时,会先找到被封闭在闭包环境的i,单击div时,会分别输出0,1,2,3,4。

<div>0</div> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <script> var divs = document.getElementsByTagName("div"); for (var i = 0; i < divs.length; i++) { divs[i].onclick = (function(num) { return function() { alert(num); }; })(i); } </script>

类似实例:闭包直接赋给数组

function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++){ result[i] = function(){ return i; }; } return result; } for (var i = 0; i < 10; i++) alert(createFunctions()[i]());

结果:result的每个元素都返回10。

说明:闭包的作用域链有明显的副作用——闭包总是获得外部函数变量的最终值。上面代码中,外部函数产生一个函数数组result并返回。函数数组中的每个元素都是一个函数,每个函数都返回 i变量。似乎每个函数应该返回每次循环的i值,即依次返回0到9,但事实是,每个函数的返回结果都是10。这是因为每个内部函数返回的是变量i,而不是i在某个时刻的特定值,而i的作用域是整个外部函数,当外部函数执行完成后,i的值是10。

解决:在每个内部函数的内部,再产生一个匿名函数并返回。

function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++) { result[i] = (function(num) { return function() { return num; }; })(i); } return result; } for (var i = 0; i < 10; i++) alert(createFunctions()[i]());

结果:result依次返回0到9。

说明:(i)使得该层匿名函数立即执行。

3、闭包

有时候需要得到函数内的局部变量。如何从外部读取局部变量?那就是在函数的内部,再定义一个函数。

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

① 闭包的原理

1) 后台执行环境中,闭包的作用域链包含着自己的作用域、函数的作用域和全局作用域。

2) 通常,函数的作用域和变量会在函数执行结束后销毁。

3) 但是,当函数返回一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。

② 闭包的特性

1) 函数内再嵌套函数。

2) 内部函数可以引用外层的参数和变量。

3) 参数和变量不会被垃圾回收机制回收。

③ 闭包的用途

1) 读取函数内部的变量。

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

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量了。

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/108a8498b2c38600d5d52d324cdc13f0.html