最近更新
阅读排行
关注本站

关于闭包

阅读:2984 次   编辑日期:2013-12-31

目录:

概述:

今天聊一个老生常谈的话题 - “闭包”,其实闭包这个问题没有必要深入的了解,因为在工作中用到的地方很少,可是在面试的过程中经常会问到,所以今天咱们简单的聊一聊。

为什么会有闭包:

首先说说为什么会有闭包,现在下面的代码:
	var a = 1;
	function uw3c(){
		alert(a);//1
	}
	uw3c();
上面代码的运行结果是“1”,这个毫无疑问。接着看下面的代码:
	function uw3c1(){
		var a = 1;
	}
	uw3c();
	alert(a);//not defined
为什么没有结果大家应该也知道,因为变量a为局部变量,在外面根本找不到这个变量。所以问题就来了,由于作用域的问题我们访问不到函数uw3c1内部的变量a,那么我们如何才能访问到呢?于是,就产生了 - “闭包”。

什么是闭包:

先写出ECMAscript中的定义 - “闭包是代码块和创建该代码块的上下文中数据的结合。”
再说说我自己的理解 - “闭包就是可以读到作用域达不到的函数内部变量的函数”

闭包的应用:

之前已经说了,函数的外部是不能访问到函数内部的变量的,但是我要想获取到怎么办?答案是,作为返回值不是就能访问到了吗?看看下面代码:
	function uw3c_1(){
		var a = 1;
		function uw3c_2(){
			alert(a);
		}
		return uw3c_2;
	}
	var test = uw3c_1();
	test();//1
看到了吧,如此一来就能在函数的外部获取到变量“a”了,这就是闭包的第一个用处,获取到函数内部的变量。还有一个用处:
	function uw3c_1(){
		var a = 1;
		uw3c_3 = function(){ a += 1;}
		function uw3c_2(){
			alert(a);
		}
		return uw3c_2;
	}
	var test = uw3c_1();
	test();//1
	uw3c_3();
	test();//2
一般的情况下,变量a会随着程序的结束而被销毁,理论上两次结果都应该为“1”,但是第二次却为2,这就是闭包的第二个用处,保存变量不被销毁。 原因是,uw3c_2作为返回值存在于全局中,但是uw3c_2是依赖于uw3c_1的,所以uw3c_1和变量a没有被删除。所以尽量不要使用闭包。

同一个上下文中创建的闭包:

同一个上下文中创建的闭包是共用一个作用域的。 也就是说,某个闭包对其中的变量做修改会影响到其他闭包对其变量的读取:
	var firstClosure;
	var secondClosure;

	function uw3c() {

	  var x = 1;

	  firstClosure = function () { return ++x; };
	  secondClosure = function () { return --x; };

	  x = 2; // 在同一个作用域中修改变量

	  alert(firstClosure()); // 3, 通过 firstClosure的作用域
	}

	uw3c();

	alert(firstClosure()); // 4
	alert(secondClosure()); // 3
所以,正是因为这个特性,在工作中大家还容易犯一个错误:
	var data = [];

	for (var k = 0; k < 3; k++) {
	  data[k] = function () {
		alert(k);
	  };
	}

	data[0](); // 3, 而不是 0
	data[1](); // 3, 而不是 1
	data[2](); // 3, 而不是 2
原因是,这些函数属于统一个作用域,所以结果一样。k会在等于2的时候停止for循环,但是自己还会在执行++,所以结果都是3,而不是2.
那么我们应该如何解决这个问题呢?思路是为每个函数单独创建作用域:
	var data = [];

	for (var k = 0; k < 3; k++) {
	  data[k] = (function _helper(x) {
		return function () {
		  alert(x);
		};
	  })(k); // 将 "k" 值传递进去
	}

	// 现在就对了
	data[0](); // 0
	data[1](); // 1
	data[2](); // 2
上述例子中,函数“_helper”创建出来之后,通过参数“k”激活。其返回值也是个函数,该函数保存在对应的数组元素中。 这种技术产生了如下效果: 在函数激活时,每次“_helper”都会创建一个新的变量对象,其中含有参数“x”,“x”的值就是传递进来的“k”的值。

总结:

以上例子如果你能看懂,一句话就能总结闭包:使用返回函数的方法获取数据。
将本篇文章分享到:
top