Closure在JavaScript中的应用

>
Closure在JavaScript中的应用

    最近一直抽出时间在看《精通JavaScript》,我觉得这本书的内容丰富程度、深度及涵盖面不亚于《JavaScript高级程序设计》。由于该书的作者也是开源JavaScript框架jQuery的创造者,所以其构建JS框架的设计理念始终贯穿本书。另外该书的另一大特点就是详细介绍了JavaScript中的一些鲜为人知的特性和实践技巧,非常适合那些想要由JavaScript初学者进阶为JavaScript高手的朋友。

    该书中提到了Closure(闭包)的概念,虽然其他的JavaScript书籍也有提到过Closure,但是我发觉看完本书后方能真正理解Closure的精髓。首先来明确一下Closure的概念:Closures are means through which inner functions can refer to the variables present in their outer enclosing function after their parent functions have already terminated.我的理解为:闭包意味着包含在外层函数里面的(内部)函数可以引用到外层函数中所定义的变量,即使外层函数的生命周期已经停止。

    这对我们来说是非常有用的:

  • 利用这种特性可以减少代码量,使代码更简洁明了。举一个例子,我们想让一个函数延迟一定毫秒后执行,并输出一定的信息,那么我们可能会编写这样的代码:

      // Define
      var msg = 'some messsage';
      // Initialize a callback that will occur in one second
      setTimeout(function(){
        // alert msg after 1000 milliseconds
        alert(msg);
      }, 1000);

      上面的代码看起来很乱,不怎么舒服。首先,我们定义一个全局变量msg,这样做很容易和其他的代码或
      JavaScript发生冲突或混淆;其次,上面的代码不够灵活,比如说间隔时间。而利用Closure就可以很轻
      松的解决上面的问题:

      function delayedAlert( msg, time ) {
        // Initialize an enclosed callback
        setTimeout(function(){
          // Which utilizes the msg passed in from the enclosing function
          alert( msg );
        }, time );
      }

  • 结合JavaScript的函数作用域(Function-Scoped)特性和匿名函数(Annoymous Function)可以是代码冲突降至最低(此法甚妙!).

      首先解释一下JavaScript的函数作用域特性,因为在JavaScript中不存在块作用域,这个和C/C++语言是
      不一样的,仅在函数中声明的函数才具有局部作用域。因此下面的代码中的if语句块中所声名的变量val
      实际上就全局变量val:

      // define a global var
      var val = 'some_value';
      // redefine val in if block
      if (true) var val = 'new_value';
      // they are the same reference of the global variable val
      // result is false.
      alert(val == 'some_value');

      其次解释一下匿名函数,没有指定函数名称的函数均可称为匿名函数,而JavaScript语法中也允许将一
      个匿名函数赋给一个变量,如:

      var fnFoo = function() {
        // do something
      };
      // call function
      fnFoo();
      结合大括号就可以构造一个自调用函数(self-executing function),代码如下:

      (function() {
        // do something
      })();

     在结合之前的“函数作用域”特性就可以构造出来可以避免命名冲突的代码,如下:

     // declare a global var
     var vGlobal = 'some_value';
     (function() {
       var vGlobal = 'your_value';
     })();
     // this time return true value with no naming conflict
     alert(vGlobal == 'some_value');

    这个就是我从《精通JavaScript》的Closure小节中体会到的我认为在代码实践中非常有用的技巧。据说很多JavaScript框架(包括jQuery和YUI等)均采用了此法来消除命名冲突的问题。

posted @ 2008-10-30 21:06  eliuhy  阅读(241)  评论(0编辑  收藏  举报