js 閉包,做用域,this 終結篇(轉)

以前有寫過閉包,做用域,this方面的文章,但如今想一想當時寫的真是廢話太多了,以致於繞來繞去的,讓新手反而更難理解了,因此就有了此篇文章,也好和閉包,做用域,this告一段落。html

    

    第一個問題:什麼是閉包?前端

    我不想回答這個問題,可是我能夠告訴你的是閉包能夠解決函數外部沒法訪問函數內部變量的問題。下面是一段沒有使用閉包的代碼:json

  function fn(){瀏覽器

    var a = 10;閉包

  }函數

     alert(a);學習

     //報錯了,由於a沒有定義,雖然函數fn裏面定義了a可是,可是它只能在函數fn中使用。也就是做用域的問題。this

   再看‘閉包能夠解決函數外部沒法訪問函數內部變量的問題’這段話,好像有點意思,那麼究竟閉包是怎麼作的,看下面代碼。調試

  function fn(){htm

        //定義了一個變量name

   var name = '追夢子';

        //我如今想在外部訪問這個變量name怎麼辦呢?哈:不是有return,我把它返回出去,我再用個變量接收一下不就能夠了,哈哈哈哈~~~~~

         return name;

      }

      var name = fn();//接收fn返回的name值。

      alert(name);//追夢子;

     ·······這裏的閉包就是利用函數的return。除了經過return還能夠經過其餘的幾種方法以下:

  

  方法1:

    

function fn(){
  var a = 0;
  b = a;
}
alert(b)

  這裏利用了js的一個特性,若是在函數中沒有用var定義變量,那麼這個變量屬於全局的,但這種方法多少有些很差。

  

  方法2:

  

var f = null;
function fn(){
  var a = 0;
  f = function(){
    a++;
    f.a = a;
  };
}
fn();
f();
alert(f.a);//1
f();
alert(f.a);//2

 

    但好像也沒有那樣神奇對吧?其實閉包還有一個很重要的特性。來看一個例子。

  var lis= document.getElementsByTagName['li']; 

  //假如這段代碼中的lis.length = 5;

      for(var i=0;i<lis.length;i++){

    lis[i].onclick = function(){

      alert(i);

    };

     }

  最終結果是無論單擊哪一個li元素都是彈5。不信你試試。爲何呢。看下面分析。

    

  for(var i=0;i<lis.length;i++){

      }

      // i = 5對吧

  lis[0].onclick = function(){

    alert(i); 

  };

  lis[1].onclick = function(){

    alert(i); 

  };

  lis[2].onclick = function(){

    alert(i);

  };

  lis[3].onclick = function(){

    alert(i);

  };

  lis[4].onclick = function(){

    alert(i);

  };

    爲何會這樣呢,由於你for循環只是給li綁定事件,可是裏面的函數代碼並不會執行啊,這個執行是在你點擊的時候才執行的好吧?可是此時的i已是5了,因此全部的都打印出5來了。

  若是想解決這個問題咱們可使用閉包,閉包的特色不僅是讓函數外部訪問函數內部變量這麼簡單,還有一個大的特色就是經過閉包咱們可讓函數中的變量持久保持。來看。

  function fn(){

    var num = 0;

   return function(){

    num+=1;

           alert(num);   

         };  

      }

      var f = fn();

      f(); //1

      f(); //2

     若是你是初學者可能沒以爲這有什麼。OK,讓你看個東西。

  function fn(){

        var num = 5;

        num+=1;

        alert(num);

     }  

    fn(); //6

    fn(); //6

     爲何呢?由於函數一旦調用裏面的內容就會被銷燬,下一次調用又是一個新的函數,和上一個調用的不相關了,不過有個特殊的狀況,看這:

  

  function fn(){

    var num = 0;

   return function(){

    num+=1;

           alert(num);   

         };  

      }

      var f = fn();

      f(); //1

      f(); //2

    

    這段代碼很簡單,不要被它欺騙了,咱們首頁定義了一個fn函數,裏面有個num默認爲0,接着返回了一個匿名函數(也就是沒有名字的函數)。咱們在外部用f接收這個返回的函數。這個匿名函數乾的事情就是把num加1,還有咱們用來調試的alert。

  這裏之因此執行玩這個函數num沒有被銷燬是由於那個匿名函數的問題,由於這個匿名函數用到了這個num,因此沒有被銷燬,一直保持在內存中,所以咱們f()時num能夠一直加。

   這裏你能夠看不懂了,之因此有這種感受是由於js回收機制你不懂,強烈建議你看我以前的再次講解js中的回收機制是怎麼一回事。這篇文章。

 

   關於閉包的知識就到這裏了,若是你想看關於閉包的案例能夠看這篇:從閉包案例中學習閉包的做用,會不會由你。

   而外:關於在for循環中綁定事件打印變量i是最後一次。

  

   而外說一句:這裏並非說return就是閉包,這裏只是強調return的重要性,若是你仍是一個新手建議你多看一些初級文章,在來看這篇文章,但願你會有新收穫。寫這篇文章一開始我也說了它的目的是回顧一下當初我沒有理解的地方,當初已經理解的這篇文章並無過多的去講。

 

 做用域居然上面已經講完了~~~

   

   大前端 369451410歡迎你的加入。

 

   那就說一下this:

  咱們常常用this,可是也許你還不清楚它是什麼吧?

     lis[i].onclick=function(){this.style.border="1px solid #ccc";} ;

     此時的this表示lis[?]它的引用。

     這裏的i不是i其實是一個準確的數字:如lis[2].onclick = function(){this.style.border="1px solid #ccc";}; this = lis[2] ;   

     簡單來講this它始終引用一個對象。

       lis[2]它也一個對象,是一個HTMLElement對象。

       其實無論什麼狀況下它都會有對象的,這個你不用操心,看

    function fn(){

     this.name = "追夢子";    

          };    

          fn();

          alert(this.name);//追夢子

          //固然也能夠這樣

    alert(name);

           雖然這段代碼中看似沒有對象,但大錯特錯,由於瀏覽器環境中默認就有一個window對象,所以你在函數中直接用this.name實際上這個this就表示window。

  var json = {

    name:'yyy',

    fn:function(){alert(this.name)} 

    };

   json.fn(); // yyy;

  fn屬於json,因此this實際上就是json。

     若是你是初學者建議你暫時先記住這三點,固然this還有不少要說的,不過作爲初學者你能夠在項目中經過console.log來檢查this是不是你預期的那樣。

     更多關於this的內容,能夠看完全理解js中this的指向,沒必要硬背。

 

     這篇文章並不算是一篇入門的教程,這篇文章主要是總結以前沒有理解的地方,或者是以一種更加簡單明瞭的方式寫的,固然是按照我本身的理解來的,不必定你能理解,sorry,好了一切就從這裏結束吧。

相關文章
相關標籤/搜索