摘要:局部變量在函數中聲明的變量,函數的參數作用域是局部性的,在函數體外,或者說的當前作用域的上層是無法直接讀取的。執行結果這樣我們就在外層取得了函數內部局部變量的也就是閉包實現從外部讀取局部變量的能力。
淺談作用域
??當我們新建一個可以儲存變量的值,怎么才能讀取到這個變量呢?能訪問到這個變量,就說明符合作用域規則,作用域規則就可以說是js引擎讀取變量的規則。
??在js中變量分為兩種,全局變量和局部變量,全局變量(擁有全局作用域)可以在整個js應用中被所有代碼訪問到,從程序開始分配內存直至結束才會被釋放(出于對代碼的性能、可讀性、以及潛在沖突考慮應該減少使用)。
??局部變量在函數中聲明的變量,函數的參數(作用域是局部性的),在函數體外,或者說的當前作用域的上層是無法直接讀取的。
??下面再說下作用域嵌套,產生作用域鏈的事,在我們實際編寫代碼的時候,比如:
var a = "a"; function demo(b) { let c = "c"; function print(c) { console.log(a + " " + b + " " + c); } print(c); } demo("b");
執行結果:
??在print方法執行的時候,會從當前的執行作用域開始查找變量,如果找不到,就繼續向上一級繼續查找,如果找到則會停止,如果沒有就會繼續直至當最后到達全局作用域時,此時無論找到還是沒找到,都會結束查找。
st=>start: 當前作用域 io1=>start: 上層作用域 io2=>start: ... cond=>end: 全局作用域 st->io1->io2->cond
??(簡單寫了個流程圖方便腦補)
??接下來還是這段代碼讓我們來做一個小小的修改。
var a = "a"; function demo(b) { let c = "c", a = "d"; function print(c) { console.log(a + " " + b + " " + c); } print(c); } demo("b");
執行結果:
??結果是輸出了上一層的變量a,這也就是作用域查找的機制,作用域始終從運行時所處的最內部作用域開始,逐漸向外層查找,當遇到第一個符合條件的結果就會返回,停止查找。
變量提升??先簡單上一段代碼
a = "a"; var a; console.log(a);
執行結果:
??為什么會有這種結果呢?聲明在后,反而打印出前面聲明得值,其實js在編譯的時候會先進行聲明操作,之后再進行賦值操作,也就是只要是在作用域中的聲明一出現,就將在代碼本身被執行前優先進行處理。也可以將這個過程理解為所有的聲明(變量和函數)都會被“提升”到作用域的最頂端。(雖然函數聲明和變量聲明都會被提升,但是函數優先級要高于變量)
(在ES6引入了let和const可以用來聲明創建塊作用域。for循環頭部定義強烈建議用let,感興趣的人可以去看看js函數作用域和塊作用域)
閉包??提到閉包很多人腦袋里都會感覺模模糊糊的,閉包在概念上定義是能夠讀取其他函數內部變量的函數,在中,只有函數內部的子函數才能讀取這個函數局部變量,這時候前面說的作用域起到作用了,所以我們現在可以這樣理解,定義在一個函數內部的函數,這個函數可以訪問其他函數的變量,就可以稱為“閉包”。
??下面來聊聊閉包的用處,主要就是。1.能夠讀取到函數內部的變量,2.可以讓變量始終保存在內存中(這點要注意后面解釋),下面上代碼。
function demo() { let a = "a"; function print() { console.log(a); } return print; } var clo = demo(); clo();
執行結果:
??這樣我們就在外層取得了demo函數內部局部變量的a,也就是閉包實現從外部讀取局部變量的能力。
??下面說一說讓變量始終保存在內存中這點.
function demo() { let a = 1; addA = () => a+=1; function print() { console.log(a); } return print; } var clo = demo(); clo(); addA(); clo();
執行結果:
??閉包可以阻止,demo內部作用域都被垃圾清理機制回收銷毀,可以看到局部變量a第二次執行比第一次+1,這就說明第一次運行結束后啊,沒有被回收,因為print()仍在使用這個作用域所以demo不會被回收。
(閉包會使得對應的變量一直保存在內存中,不會被清理回收,對內存消耗大,別濫用)
??1.原生的setTimeout傳遞的函數不能帶參數
//會報錯 function func(param){ console.log(param); } var test = func(1); setTimeout(test, 1000); //通過閉包實現傳參效果 function func(param){ return function(){ console.log(param); } } var test = func(1); setTimeout(test, 1000);
??2.封裝變量
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102721.html
摘要:有何區別在中,存在關鍵字,它聲明的變量同樣存在塊級作用域。而且函數本身的作用域,只存在其所在的塊級作用域之內,例如重復聲明一次函數上面這段代碼在中的輸出結果為因為被條件語句中的上升覆蓋了。如果對的使用,或的其他新特性感興趣,請自行閱讀文檔。 引子 首先大家看一下下面的代碼,猜猜會輸出什么結果? var foo = 1; function bar() { if (!foo) { ...
摘要:盡可能的使用局部變量,少用全局變量。正確的實現就是在函數體內部使用將聲明成局部變量。在新特性中,引入了塊級作用域這個概念,因此還可以使用,來聲明局部變量。它們共享外部變量,并且閉包還可以更新的值。 變量作用域 作用域,對于JavaScript語言來說無處不在,變量作用域,函數作用域(運行時上下文和定義時上下文),作用域污染等等都跟作用域息息相關,掌握JavaScript作用于規則,可以...
摘要:閉包是什么這是一個在面試的過程中出現的概率為以上的問題,也是我們張口就來的問題。文章推薦我們面試中在被問到閉包這個問題是要注意的幾點閉包的延伸,讓面試變得 閉包是什么?這是一個在面試的過程中出現的概率為60%以上的問題,也是我們張口就來的問題。但是我們往往發現,在面試的過程中我們的回答并不那么讓面試官滿意,我們雖然能張口說出一些但是卻不能系統的對這個問題進行回答。面試官希望加入自己團隊...
摘要:垃圾回收內存管理實踐先通過一個來看看在中進行垃圾回收的過程是怎樣的內存泄漏識別在環境里提供了方法用來查看當前進程內存使用情況,單位為字節中保存的進程占用的內存部分,包括代碼本身棧堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術棧 | https:...
閱讀 1525·2023-04-26 00:25
閱讀 918·2021-09-27 13:36
閱讀 933·2019-08-30 14:14
閱讀 2177·2019-08-29 17:10
閱讀 1015·2019-08-29 15:09
閱讀 1950·2019-08-28 18:21
閱讀 970·2019-08-26 13:27
閱讀 977·2019-08-26 10:58