`

什么是javascript闭包

    博客分类:
  • js
 
阅读更多

闭包(closure)是 ECMAScript 的语法特性,即在函数内部定义函数,内部的函数可访问其外部函数的作用域,JavaScript 也实现了这种特性。闭包这个术语确实晦涩,但实现闭包其实很简单,只要弄懂了 JS 的作用域规则,自然就好理解闭包了。
举个例子,

 
function outer(name){ // 外部的函数
  var msg="hello";
  function inner(){ // 内部函数
    alert(msg+" "+name);
  }
  return inner(); // 返回内部函数
}
var clos=outer("Wang");
clos();

这段代码就使用了闭包,执行代码将弹出警告“hello Wang”。


先解释一下作用域(scope)。在运行函数都会创建属于函数的上下文环境(context)及作用域,作用域即当前环境范围内的变量。JS 中最外围的环境为 window 对象,也就是全局作用域所在的环境。当执行到下一级环境时,下一级环境会主动包含上一级的作用域,最终形成一级一级关联的作用域链(对象的 [[Scope]] 属性指向该作用域链)。当有下一级环境生成时,上一级环境会失活,但不会自动销毁而保存在一种“栈”式结构中,这样可以保证作用域链的延续性,也可以环境回退时再次激活。当前环境可访问当前作用域链中的全部变量,比如上面代码中的 inner() 函数可访问 outer() 函数中的 msg 和 name 变量。
闭包就是借助这种作用域链,一方面可使内部函数可访问外部函数的变量;另一方面,闭包还可以抑制外部函数环境的销毁,使其变量始终保存在内存中,直至不需要时再销毁。至于闭包的应用,实际上都是一些小技巧,下面写一些例子。


循环绑定事件,使循环过程中的索引值 i 均有效

 
var elems=document.getElementsByTagName('li');
for(var i=0;i<elems.length;i++){
  elems[i].onclick=function(i){
    return (function(){ // 闭包
      alert(i);
    })
  }(i); // 这里使用了匿名函数,实际应用中较常见
}

构造无参数的函数名引用,因为闭包的函数一般没有参数

 
//使用之前 outer 函数的例子
var clos=outer("Wang");
setTimeout(clos,100);

模块封装,比如在 jQuery 中就有类似的代码,保证内部变量不影响全局变量

 
function($){ 
  // jQuery 内部实现
})(jQuery);
// 这里使用了自动执行的匿名函数,即定义匿名函数并立即执行。看起来和闭包没什么关系,但原来是一样的。

 

但是,闭包最好要少用,之前已经说过,闭包会使变量始终保存在内存中,如果不当使用会增大内存开销,甚至会带来内存泄漏的风险。当然,还是可以使用类似

 
//使用之前 outer 函数的例子
clos=null;

的代码释放变量占用的内存并帮助 GC 机制回收。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics