《javascript面向对象编程指南》——闭包

闭包:有权访问另一个函数作用域中的变量的函数,这样的话每个函数都可以被认为是一个闭包。但是大多数时候,该作用域在函数体执行完之后就自行销毁了

如果一个函数会在其父级函数返回之后留住对父级作用域链的话,相关闭包就会创建

首先是一个一般函数

var a = "global variable";
var F = function() {
	var b = "local variable";
	var N = function() {
		var c = "inner local";
	};
};

从全局到最里面的作用域链依次是:

  • a、F()
  • b、N()
  • c

现在将N的空间扩展到F以外,并止步于全局空间以内,就产生闭包

var a = "global variable";
var F = function() {
	var b = "local variable";
	var N = function() {
		var c = "inner local";
		return b;
	};
	return N;
};

var inner = F();
inner();	//"local variable"

如上,只需在F空间return出N空间,然后将F()的调用赋值给全局变量inner,此时inner就是N函数,调用一下inner(),就相当于执行N(),但是这里N(),既可以访问其原有的作用域,也是全局函数

上述步骤就是突破作用域链

下面这种闭包,不是F()返回函数,而是直接在函数体内N赋值给全局变量inner

var inner;
var F = function() {
	var b = "local variable";
	var N = function() {
		return b;
	};
	inner = N;
};

F();		//需要调用,才能将N赋值给inner
inner();	//"local variable"

相关定义与闭包

如果一个函数会在其父级函数返回之后留住对父级作用域链的话,相关闭包就会创建

function F(param) {
	var N = function() {
		return param;
	};
	param++;
	return N;
}

var inner = F(123);
inner();	//124

如上,当返回的函数被调用时,param++已经执行过一次递增操作了,所以inner()返回的是被更新后的值

由此,函数所绑定的是作用域本身,而不是在函数定义时该作用域中的变量或变量当前返回的值

循环中的闭包

如下,是一个三次循环操作,每次迭代中都会创建一个返回当前循环序号的新函数

function F() {
	var arr = [],
		i;
	for (i = 0; i < 3; i++) {
		arr[i] = function() {
			return i;
		};
	}
	return arr;
}

var newArr = F();
console.log(newArr[0]());	//3
console.log(newArr[1]());	//3
console.log(newArr[2]());	//3

如上,结果都是3

我们在这里创建了三个闭包,而他们都指向了一个共同的局部变量i。但是,如上节所说,闭包并不会记录他们的值,他们所拥有的只是相关域在创建时的一个连接(引用)

当循环结束时i的值为3,所以这三个函数都指向这一个共同值(注意不是2)

解决1

function F() {
	var arr = [],
		i;
	for (i = 0; i < 3; i++) {
		arr[i] = (function(x) {
			return function() {
				return x;
			};
		})(i);
	}
	return arr;
}

var newArr = F();
console.log(newArr[0]());
console.log(newArr[1]());
console.log(newArr[2]());

如上,将i传递给另一个即时函数

解决2

function F() {
	function binder(x) {
		return function() {
			return x;
		};
	}
	var arr = [],
		i;
	for (i = 0; i < 3; i++) {
		arr[i] = binder(i);
	}
	return arr;
}

var newArr = F();
console.log(newArr[0]());
console.log(newArr[1]());
console.log(newArr[2]());

如上,定义一个内部函数,将i本地化

posted @ 2016-05-05 22:53  u14e  阅读(152)  评论(0编辑  收藏  举报