javascript變量提升和閉包理解
我們先來(lái)看一個(gè)題目:
<script> console.log(typeof a)//undefined var a='littlebear'; console.log(a)//littlebear </script> <script> console.log(typeof a)//string var a=1; console.log(a)//1 </script>
第一個(gè)script里可以看出var a 被提升到頂部,a = 'littlebear'被保留在原地。
第二個(gè)script,之所以不先打印undefined ,是因?yàn)閍在上面已經(jīng)被var聲明過(guò),所以var a不會(huì)再次被提升。
再看一個(gè)題目:
<script> console.log(a)//function a(){} var a=1; console.log(a)//1 function a(){} console.log(a)//1 </script>
可以看到function a(){}被提升到最頂端。說(shuō)明函數(shù)的提升變量的提升
1.變量提升
在ES6之前,JavaScript沒有塊級(jí)作用域(一對(duì)花括號(hào){}即為一個(gè)塊級(jí)作用域),只有全局作
用域和函數(shù)作用域。變量提升即將變量聲明提升到它所在作用域的最開始的部分。
上個(gè)簡(jiǎn)歷的例子如:
console.log(global); // undefined var global = 'global'; console.log(global); // global function fn () { console.log(a); // undefined var a = 'aaa'; console.log(a); // aaa } fn();
之所以會(huì)是以上的打印結(jié)果,是由于js的變量提升,實(shí)際上上面的代碼是按照以下來(lái)執(zhí)行的:
var global; // 變量提升,全局作用域范圍內(nèi),此時(shí)只是聲明,并沒有賦值 console.log(global); // undefined global = 'global'; // 此時(shí)才賦值 console.log(global); // 打印出global function fn () { var a; // 變量提升,函數(shù)作用域范圍內(nèi) console.log(a); a = 'aaa'; console.log(a); } fn();
2.函數(shù)提升
js中創(chuàng)建函數(shù)有兩種方式:函數(shù)聲明式和函數(shù)字面量式。只有函數(shù)聲明才存在函數(shù)提升!如:
console.log(f1); // function f1() {} console.log(f2); // undefined function f1() {} var f2 = function() {}
之所以會(huì)有以上的打印結(jié)果,是由于js中的函數(shù)提升導(dǎo)致代碼實(shí)際上是按照以下來(lái)執(zhí)行的:
function f1() {} // 函數(shù)提升,整個(gè)代碼塊提升到文件的最開始 console.log(f1); console.log(f2); var f2 = function() {}
3.什么是閉包
閉包是有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域的變量的函數(shù)。
簡(jiǎn)單的說(shuō),Javascript允許使用內(nèi)部函數(shù)---即函數(shù)定義和函數(shù)表達(dá)式位于另一個(gè)函數(shù)的函數(shù)體內(nèi)。而且,這些內(nèi)部函數(shù)可以訪問(wèn)它們所在的外部函數(shù)中聲明的所有局部變量、參數(shù)和聲明的其他內(nèi)部函數(shù)。當(dāng)其中一個(gè)這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時(shí),就會(huì)形成閉包。
4.變量的作用域
要理解閉包,首先要理解變量的作用域。
變量的作用域無(wú)非就是兩種:全局變量和局部變量。
Javascript語(yǔ)言的特殊之處,就在于函數(shù)內(nèi)部可以直接讀取全局變量。
其中內(nèi)部函數(shù)中可以訪問(wèn)外部函數(shù)的變量,是因?yàn)閮?nèi)部函數(shù)的作用域鏈中包含了外部函數(shù)的作用域;
也可以理解為:內(nèi)部函數(shù)的作用范圍輻射到了外部函數(shù)的作用范圍;
var n=999; function f1(){ alert(n); } f1(); // 999
另一方面,在函數(shù)外部自然無(wú)法讀取函數(shù)內(nèi)的局部變量。
function f1(){ var n=999; } alert(n); // error
這里有一個(gè)地方需要注意,函數(shù)內(nèi)部聲明變量的時(shí)候,一定要使用var命令。如果不用的話,你實(shí)際上聲明了一個(gè)全局變量!
function f1(){ n=999; } f1(); alert(n); // 999
5.閉包的寫法和用法
var Circle={ "PI":3.14159, "area":function(r){ return this.PI * r * r; } }; alert( Circle.area(1.0) );//3.14159
剛開始我沒意識(shí)到,這樣寫對(duì)象也是一種閉包,今天回頭想想,這就是閉包的經(jīng)典用發(fā)啊!
6.使用閉包的注意點(diǎn)
1)由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
2)閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
相關(guān)文章
Web打印解決方案之證件套打的實(shí)現(xiàn)思路
這篇文章主要介紹了Web打印解決方案之證件套打的實(shí)現(xiàn)思路的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08JavaScript限定復(fù)選框的選擇個(gè)數(shù)示例代碼
有10個(gè)復(fù)選框,用戶最多只能勾選3個(gè),否則就灰掉所有復(fù)選框,具體實(shí)現(xiàn)思路及代碼如下,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-08-08JavaScript判斷數(shù)字是否為質(zhì)數(shù)的方法匯總
這篇文章主要介紹了JavaScript判斷數(shù)字是否為質(zhì)數(shù)的方法匯總的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06JavaScrip調(diào)試技巧之?dāng)帱c(diǎn)調(diào)試
本篇文章給大家介紹javascript調(diào)試技巧之?dāng)帱c(diǎn)調(diào)試,主要介紹使用Firebug、debugger、debugger在程序中加入斷點(diǎn)調(diào)試等,但是這些調(diào)試技巧都不借助于瀏覽器之外的工具,其他瀏覽器主要是opera、safari、chrome和ie8,感興趣的小伙伴一起看看吧2015-10-10JavaScript學(xué)習(xí)小結(jié)之被嫌棄的eval函數(shù)和with語(yǔ)句實(shí)例詳解
這篇文章主要介紹了JavaScript學(xué)習(xí)小結(jié)之被嫌棄的eval和with實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-08-08JavaScript對(duì)象和字串之間的轉(zhuǎn)換實(shí)例探討
從對(duì)象的格式可以看出,如果字串的格式定義成 json 格式的, 就可以直接轉(zhuǎn)換為obj了,感興趣的朋友可以參考下哈2013-04-04