之前有寫過閉包,作用域,this方面的文章,但現在想想當時寫的真是廢話太多了,以至於繞來繞去的,讓新手反而更難理解了,所以就有了此篇文章,也好和閉包,作用域,this告一段落。 第一個問題:什麼是閉包? 我不想回答這個問題,但是我可以告訴你的是閉包可以解決函數外部無法訪問函數內部變數的問題。下麵是一 ...
之前有寫過閉包,作用域,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中的回收機制是怎麼一回事。這篇文章。
關於閉包的知識就到這裡了,如果你想看關於閉包的案例可以看這篇:從閉包案例中學習閉包的作用,會不會由你。
而外說一句:這裡並不是說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,好了一切就從這裡結束吧。