摘要:詞法作用域是一種靜態作用域這個例子的結果按靜態作用域來分析執行函數,先從函數內部查找是否有局部變量,如果沒有,就根據書寫的位置,查找上面一層的代碼,也就是等于,所以結果會打印。靜態作用域,決定的是作用域鏈的順序。
博客原文地址:https://finget.github.io/2018/03/01/javascriptPrecompile/
看不明白的地方歡迎提問,有理解的不對的地方希望能夠指出來
JavaScript預編譯JavaScript在運行時,要經歷三步
語法分析 2.預編譯 3.解析執行(自上而下)
先思考這么一個題
function fn (a) { console.log(a); var a = 123; console.log(a); function a(){}; console.log(a); var b =function (){}; console.log(b); } fn(1);預編譯四部曲
創建AO對象 Activation Object(執行期上下文)
找形參和變量聲明,將變量和形參名作為AO屬性名,值為undefined
將實參值和形參統一
在函數體里面找函數聲明,值賦予函數體
這四步的權重比4>3>2>1,也就是一個覆蓋的過程.
函數聲明在變量聲明的前面
函數聲明才存在變量提升。即function a(){};,而var b =function (){};不會提升。詳細分析 先看一個面試中常遇到的問題
console.log(a); // function a(){} var a = 1; function a(){};
逐行執行,在AO中是:
AO{ a: undefied } AO{ a: function(){} }換一換
var a = 1; console.log(a); // 1 function a(){};
逐行執行,在AO中是:
AO{ a: undefied } AO{ a: function(){} } // js是自上而下執行的,先執行var a = 1; 所有AO中的a就被覆蓋 AO{ a: 1 }按步驟分析文章開頭的例子
第一步
AO{ }
第二步
AO{ a: undefined, b: undefined }
第三步
AO{ a: 1, b: undefined }
第四步
AO{ a: function a(){}, b: undefined }解釋執行
執行的時候:
AO{ a: function a(){}, b: undefined } // a = 123; AO{ a: 123, b: undefined }結果:
function fn (a) { console.log(a); // function(){} var a = 123; console.log(a); // 123 function a(){}; console.log(a); // 123 var b =function (){}; console.log(b); // function(){} } fn(1);加入window,全局環境
global = 100; function fn() { console.log(global); global = 200; console.log(global); var global = 300; } fn(); var global;
在全局環境中會生成一個 GO對象 (Global Object),還是按照上面的四步執行。
GO { global: undefined }
// 執行到 global = 100 :
GO { global: 100 }
當執行fn之前會先生成一個AO:
AO { global: undefined }
所以第一次打印global是undefined。
這個時候雖然全局變量中的global已經是100,但是fn函數中自己有global變量,所以不會引用全局中的。
當執行到global = 200 :
AO { global: 200 }
所以第二次打印global是200
這里這中情況涉及到了‘作用域’。作用域
這里參考的是https://github.com/mqyqingfeng/Blog/issues/3,可以去詳細看看
JavaScript 采用的是詞法作用域,函數的作用域在函數定義的時候就決定了。
詞法作用域是一種靜態作用域
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar();
這個例子的結果:1
按靜態作用域來分析執行 foo 函數,先從 foo 函數內部查找是否有局部變量 value,如果沒有,就根據書寫的位置,查找上面一層的代碼,也就是 value 等于 1,所以結果會打印 1。
JavaScript的預編譯過程來分析這里有全局的環境:
// 這里我就寫最后一步了 GO { value: 1, foo: function() {console.log(value)}, bar: function() {var value = 2; foo()} } // 函數在執行時也會生成自己的AO fooAO{ // 沒有 } barAO{ value: 2, foo: foo() }
foo函數中沒有定義value,所以它會到它所在的上一層去找,并不會去bar里面找
把這個題做一個小小的改變:var value = 1; function foo() { console.log(value); } function bar() { value = 2; foo(); } bar();
這樣結果就是2了。
在bar函數中不定義value,而是讓它直接改變value的值,他自己沒有定義,它也會去全局GO里面找,這樣bar里面的value和全局中的value就是同一個內存中的數,當代碼執行到value=2,再執行foo()時,全局中的value也是2,所以輸出2。在第一種,情況中,var value=2只改變了barAO中的值。
再來,我們再變一下:function foo() { console.log(value); } function bar() { value = 2; foo(); } bar();
結果還是2.
這次我們沒有全局定義value,在bar中也沒有定義,而是直接賦值。在JavaScript中如果一個變量未聲明就直接賦值,那么這個變量就是個全局變量。所以GO中會定義一個value:2,foo也沒有去bar里面找value。
靜態作用域,決定的是作用域鏈的順序。最后思考一個問題
function fn(){ var a = b = 100; console.log(window.a); console.log(window.b); }
var a = b =100;
先將100賦值給b,即b=100,此時b沒有聲明就被賦值。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94879.html
摘要:預編譯發生在函數執行前也就是說函數執行時,預編譯已經結束。五總結理解預編譯需要明白變量函數聲明和變量賦值。預編譯階段,只進行變量函數聲明,不會進行變量的初始化即變量賦值,所有變量的值都是變量賦值是在解釋執行階段才進行的。 一、JS的概念 JavaScript ( JS ) 是一種具有函數優先的輕量級解釋型或即時編譯型的編程語言。 二、JS語言特點 2.1 單線程 (1)JavaScri...
摘要:關于兩個專業術語的討論起自對你不知道的一書的閱讀學習。遇到,編譯器會詢問作用域是否已經有一個該名稱的變量存在于同一個作用域的集合中。摘錄來自你不知道的。 JS 編譯之 LHS RHS 一、前言 最近和朋友聊技術的時候,聊到 LHS RHS,我竟然沒聽說過 沒聽說過。。。 于是成功引起了我的好奇心。 關于兩個專業術語的討論起自對《你不知道的JavaScript》一書的閱讀學習。 二、編譯...
摘要:結果結果函數定義式函數表達式結果預編譯是以段為處理單元結果作用域鏈代碼優化在標識符解析的時候,查找全局變量是最慢的,所以盡量使用局部變量。全局變量的被調用兩次,查找該變量必須遍歷整個作用域鏈,耗費時間可以把它存儲到局部變量里再使用。 作用域屬性是在定義函數的時候決定的,不是在調用函數的時候決定。 JavaScript中的函數運行在它們被定義的作用域里,而不是它們被執行的作用域里。 ...
摘要:每一個運行期上下文都和一個作用域鏈關聯。這個對象將被推入作用域鏈的頭部,這意味著函數的所有局部變量現在處于第二個作用域鏈對象中,因此訪問代價更高了。在代碼塊內部,函數的所有局部變量將會被放在第二個作用域鏈對象中。 參考: Javascript作用域原理 理解 JavaScript 作用域和作用域鏈 JavaScript 作用域 作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數...
摘要:函數表達式又名匿名函數為變量賦的值是函數定義本身。在語言里任何匿名函數都是屬于對象。這種情況下,就叫做回調函數。如上面代碼示例展示了文檔單擊事件時以冒泡模式傳遞給回調函數的特別適用于事件驅動編程,因為回調模式支持程序以異步方式運行。 JavaScript設計模式的作用是提高代碼的重用性,可讀性,使代碼更容易的維護和擴展 在javascript中,函數是一類對象,這表示他可以作為參數傳遞...
閱讀 788·2021-10-09 09:44
閱讀 692·2019-08-30 13:55
閱讀 3153·2019-08-29 15:07
閱讀 3218·2019-08-29 13:09
閱讀 2413·2019-08-29 11:10
閱讀 1289·2019-08-26 14:05
閱讀 3591·2019-08-26 13:57
閱讀 2206·2019-08-23 16:42