摘要:是典型的詞法作用域的語言,即一個符號參照到語境中符號名字出現的地方,局部變量缺省有著詞法作用域。沒有任何自己的局部變量,然而它可以訪問到外部函數的變量,即可以使用父函數中聲明的變量。通常,函數中的局部變量僅在函數的執行期間可用。
Lexical Scope:詞法作用域本文從屬于筆者的JavaScript 入門與最佳實踐系列文章,同時,本部分內容也歸納于筆者的我的校招準備之路:從Web前端到服務端應用架構這篇綜述。
大部分人都會做錯的經典JS閉包面試題
how-do-javascript-closures-work
functions are executed using the scope chain that was in effect when they were defined
一般來說,在編程語言里我們常見的變量作用域就是詞法作用域與動態作用域(Dynamic Scope),絕大部分的編程語言都是使用的詞法作用域。詞法作用域注重的是所謂的Write-Time,即編程時的上下文,而動態作用域以及常見的this的用法,都是Run-Time,即運行時上下文。詞法作用域關注的是函數在何處被定義,而動態作用域關注的是函數在何處被調用。JavaScript是典型的詞法作用域的語言,即一個符號參照到語境中符號名字出現的地方,局部變量缺省有著詞法作用域。此二者的對比可以參考如下這個例子:
function foo() { console.log( a ); // 2 in Lexical Scope ,But 3 in Dynamic Scope } function bar() { var a = 3; foo(); } var a = 2; bar();
看一個實例如下:
var scope = "I am global"; function whatismyscope(){ var scope = "I am just a local"; function func() {return scope;} return func; } whatismyscope()()
該代碼片最終輸出的結果是:
I am just a localClosure
閉包本身是含有自由變量的代碼塊,在JavaScript中我們常用的閉包則是本身的詞法作用域與變量保留相結合的表現,首先回顧下一個基本的詞法作用域的用法:
function init() { var name = "Mozilla"; function displayName() { alert(name); } displayName(); } init();
函數 init() 創建了一個局部變量 name,然后定義了名為 displayName() 的函數。displayName() 是一個內部函數——定義于 init() 之內且僅在該函數體內可用。displayName() 沒有任何自己的局部變量,然而它可以訪問到外部函數的變量,即可以使用父函數中聲明的 name 變量。注意,這里是直接執行外部的init函數,下面看一個閉包的例子:
function makeFunc() { var name = "Mozilla"; function displayName() { alert(name); } return displayName; } var myFunc = makeFunc(); myFunc();
運行這段代碼的效果和之前的 init() 示例完全一樣:字符串 "Mozilla" 將被顯示在一個 JavaScript 警告框中。其中的不同 — 也是有意思的地方 — 在于 displayName() 內部函數在執行前被從其外圍函數中返回了。這段代碼看起來別扭卻能正常運行。通常,函數中的局部變量僅在函數的執行期間可用。一旦 makeFunc() 執行過后,我們會很合理的認為 name 變量將不再可用。雖然代碼運行的沒問題,但實際并不是這樣的。這個謎題的答案是 myFunc 變成一個閉包了。 閉包是一種特殊的對象。它由兩部分構成:函數,以及創建該函數的環境。環境由閉包創建時在作用域中的任何局部變量組成。在我們的例子中,myFunc 是一個閉包,由 displayName 函數和閉包創建時存在的 "Mozilla" 字符串形成。
避免閉包在真實的開發中我們常常會使用閉包這一變量保留的特性來傳遞變量到異步函數中,不過閉包也往往會使程序出乎我們的控制,譬如在下面這個簡單的循環中,我們本希望能夠打印出0~9這幾個數:
for(var i = 0;i < 10;i++){ setTimeout(()=>{console.log(i),1000}) }
不過所有輸入的i的值都是10,這與我們的期望產生了很大的偏差。因此我們在部分情況下需要破壞閉包而獲取真實的變量值。
將異步獲取值保留到新增的閉包中我們可以考慮加一層閉包,將i以函數參數形式傳遞給內層函數:
function init3() { var pAry = document.getElementsByTagName("p"); for( var i=0; i或者在新增的閉包中將i以局部變量形式傳遞給內部函數中:
function init4() { var pAry = document.getElementsByTagName("p"); for( var i=0; i將變量值保留到作用域之外 在DOM環境中,我們可以將變量值存儲到要操作的DOM對象中:
function init() { var pAry = document.getElementsByTagName("p"); for( var i=0; i也可以將變量i保存在匿名函數本身:
function init2() { var pAry = document.getElementsByTagName("p"); for( var i=0; i
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80118.html
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
摘要:一言以蔽之,閉包,你就得掌握。當函數記住并訪問所在的詞法作用域,閉包就產生了。所以閉包才會得以實現。從技術上講,這就是閉包。執行后,他的內部作用域并不會消失,函數依然保持有作用域的閉包。 網上總結閉包的文章已經爛大街了,不敢說筆者這篇文章多么多么xxx,只是個人理解總結。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結與《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。所以本文中將以維基百科中的定義為準即在計算機科學中,閉包,又稱詞法閉包或函數閉包,是引用了自由變量的函數。 閉包(closure)是JavaScript中一個神秘的概念,許多人都對它難以理解,我也一直處于似懂非懂的狀態,前幾天深入了解了一下執行環境以及作用域鏈,可戳查看詳情,而閉包與作用域及作用域鏈的關系密不可分,所...
摘要:建筑的頂層代表全局作用域。實際的塊級作用域遠不止如此塊級作用域函數作用域早期盛行的立即執行函數就是為了形成塊級作用域,不污染全局。這便是閉包的特點吧經典面試題下面的代碼輸出內容答案個如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫在前面 這一系列的筆記是在《javascript高級程序設計》讀書筆記系列的升華版本,旨在將零碎...
閱讀 2160·2021-11-12 10:36
閱讀 2154·2021-09-03 10:41
閱讀 2769·2021-08-19 10:57
閱讀 1238·2021-08-17 10:14
閱讀 1495·2019-08-30 15:53
閱讀 1216·2019-08-30 15:43
閱讀 979·2019-08-30 13:16
閱讀 2988·2019-08-29 16:56