1. 程式人生 > >js 閉包,作用域,this 終結篇(轉)

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

~~ fun 點擊 結束 終結篇 nbsp 重要 它的 定義變量

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

 

第一個問題:什麽是閉包?

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

  function fn(){

    var a = 10;

  }

alert(a);

//報錯了,因為a沒有定義,雖然函數fn裏面定義了a但是,但是它只能在函數fn中使用。也就是作用域的問題。

  再看‘閉包可以解決函數外部無法訪問函數內部變量的問題’這段話,好像有點意思,那麽究竟閉包是怎麽做的,看下面代碼。

  function fn(){

//定義了一個變量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,好了一切就從這裏結束吧。

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