闭包

97 阅读3分钟

闭包 —— 有权访问另一个函数作用域中的变量的函数, 即要满足以下四个条件:

  • 函数A套函数B
  • 函数A中有一个变量a
  • 函数B引用变量a
  • 当函数B在定义它的作用域A以外的地方被调用时,它访问的依然是定义它时的作用域A。这种现象称之为闭包。
function A(){
  var a = 1;
  
  function B(){
    return a;
  }
  return B;
}
var C=A();
C();

函数B嵌套在函数A内部;函数A返回函数B。这样在执行完var C=A( )后,变量C实际上是指向了函数B,再执行C( )后就会返回值a。这段代码其实就创建了一个闭包,因为函数A外的变量C引用了函数A内的函数B,也就是说:当函数A的内部函数B被函数A外的一个变量引用的时候,就创建了一个闭包。

闭包的注意事项 通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2));  // 7
console.log(add10(2)); // 12
// 释放对闭包的引用
add5 = null;
add10 = null;

add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。最后通过 null 释放了 add5 和 add10 对闭包的引用。

闭包closure()只能取得包含函数func()中任何变量的最后一个值,这是因为闭包所保存的是整个变量对象,而不是某个特殊的变量。

function f(){
	var arr=[],i;
	for(i=0;i<3;i++){
		arr[i] = function(){
			return i;
		}
	}
	return arr;
}
var func = f();
> func
结果:[function, function, function]
> func[0]
结果:   function (){
            return i;
        }

为什么是 i 而不是具体某个值?

主要是因为闭包中局部变量是【引用】而不是拷贝,也就是说,这个时候的i仅仅只是i的引用而不是i的值。而因为是i的引用,所以到了外部函数执行完毕后(i已经加到10了),这个时候,i才被赋值给result数组,而此时,i的值为10

再举个例子

function say888() {
    var num = 887;
    var sayAlert = function() { alert(num); }
    num++;
    return sayAlert;
}
say888() => 888

如果要改变上面的那种情况,可以利用匿名函数的自我执行

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

这个时候的匿名函数相当于fn(0),fn(1),fn(2), 此时,数组result中保存的是函数

result[0]() = 0;
result[1]() = 1;
result[9]() = 9;

因为这个时候的 i 只是函数参数,而函数参数是按值传递的(不是按引用传递),所以这个时候匿名函数被强制执行。