摘要:如下代碼輸出的結果是代碼執行分為兩個大步預解析的過程代碼的執行過程預解析與變量聲明提升程序在執行過程中,會先將代碼讀取到內存中檢查,會將所有的聲明在此進行標記,所謂的標記就是讓解析器知道有這個名字,后面在使用名字的時候不會出現未定義的錯誤。
如下代碼輸出的結果是?
var num = 123; function foo1(){ console.log( num ); //undefined var num = 456; console.log( num ); //456 } foo1();
Javascript代碼執行分為兩個大步:
預解析的過程
代碼的執行過程
程序在執行過程中,會先將代碼讀取到內存中檢查,會將所有的聲明在此進行標記,所謂的標記就是讓JS解析器知道有這個名字,后面在使用名字的時候不會出現未定義的錯誤。這個標記過程就是提升。
聲明:
名字的聲明,標識符聲明(變量名聲明)
名字的聲明就是讓解析器知道有這個名字
名字沒有任何數據與之對應
函數的聲明
函數聲明包含兩部分
函數聲明與函數表達式有區別,函數聲明是多帶帶寫在一個結構中,不存在任何語句,邏輯判斷等結構中
function f() {} function func() { // 函數聲明 } if ( true ) { function func2 () {} //函數表達式 } var f = function func3 () {}; //函數表達式 this.sayHello = function () {}; //函數表達式 var i= 1; function func4 () {} // 函數聲明 var j = 2; }
首先函數聲明告訴解析器有這個名字存在,該階段與名字聲明一樣
告訴解析器,這個名字對應的函數體是什么
var num = 1; function num () { alert( num ); } num(); // 報錯
分析
預解析代碼,提示名字
首先提升名字num
再提升函數名,但是名字已經存在,因此只做第二部,讓名字與函數體對應上
結論就是 代碼中已經有一個函數 num 了
開始執行代碼,第一句話從賦值語句開始執行
給num賦值為1
覆蓋了函數
調用num,由于num中存儲的是數組1,因此報錯
2.代碼分析舉例 程序1var num = 123; function foo1(){ console.log( num ); //undefined var num = 456; console.log( num ); //456 } foo1();
預解析,提升 num 名字和 foo1 函數
執行第一句話:num = 123;
執行函數調用
函數調用進入函數的一瞬間也要進行預解析,此時解析的是變量名 num
在函數內部是一個獨立的空間,允許使用外部的數據,但是現在 num 聲明同名,即覆蓋外面的
執行第一句 打印num,沒有數據,undefined
執行第二句 賦值:num = 456;
執行第三句 打印num,結果456
程序2if ( ! "a" in window ) { var a = 123; } console.log( a );
首先,預解析,讀取提升 a ,有一個名字 a 存在了
其次,in 運算符:判斷某一個字符串描述的屬性名是否在對象中
var o = { name:"jim" }; "name" in o,"age" in o
執行第一個判斷:! "a" in window
"a" in window 結果為真
!得到假
if內部的賦值不進行
最后,打印結果 a 的值為 undefined
程序3if ( false ) { function f1 () { console.log( "true" ); } } else { function f1 () { console.log( "false" ); } } f1();
預解析:提升 f1 函數,只保留提升后的內容,所以打印是 false
執行代碼,第一句話就是一個空的if結構
if ( true ) { } else { }
執行函數調用,得到 false
3.問題function foo () } {} var foo = function () {};
上面的語法是聲明,可以提升,因此在函數上方也可以調用
下面的語法是函數表達式,函數名就是foo ,他會提升,提升的不是函數體
函數表達式也是支持名字語法
var foo = function func1 () {}; func();
函數有一個屬性name,表示的是函數名,只有帶有名字的函數定義,才會有name屬性值,否則是“”
但是,函數表達式的名字,只允許在函數內部使用,IE8可以訪問
()可以將數據轉化為表達式
新的瀏覽器中,寫在if、while、do..while結構中的函數,都會將函數的聲明轉換成特殊的函數表達式
將代碼
if (...) { function foo () { ... } }
轉換成
if (...) { var foo = function foo () { .... } }
完。
推薦閱讀
進擊JavaScript之(二)詞法作用域與作用域鏈
進擊JavaScript之(三)玩轉閉包
進擊JavaScript之(四)原型與原型鏈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80050.html
摘要:匿名函數是不能單獨寫的,所以就提不上立即執行了。六立即執行函數在閉包中的應用立即執行函數能配合閉包保存狀態。來看下上節內容中閉包的例子現在,我們來利用立即執行函數來簡化它第一個匿名函數執行完畢后,返回了第二個匿名函數。 前面的閉包中,提到與閉包相似的立即執行函數,感覺兩者還是比較容易弄混吧,嚴格來說(因為犀牛書和高程對閉包的定義不同),立即執行函數并不屬于閉包,它不滿足閉包的三個條件。...
摘要:中沒有可執行的函數了,執行完出棧。當某個函數被調用時,會創建一個執行環境及相應的作用域鏈。檢查當前環境中的函數聲明使用聲明的。確定指向所以說的指向,是在函數執行時確定的。 理解js 的執行過程是很重要的,比如,作用域,作用域鏈,變量提升,閉包啊,要想明白這些,你就得搞懂函數執行時到底發生了什么! 一、執行環境(Execution Context)又稱執行上下文 當代碼執行時都會產生一個...
摘要:一作用域域表示的就是范圍,即作用域,就是一個名字在什么地方可以使用,什么時候不能使用。概括的說作用域就是一套設計良好的規則來存儲變量,并且之后可以方便地找到這些變量。 一、作用域 域表示的就是范圍,即作用域,就是一個名字在什么地方可以使用,什么時候不能使用。想了解更多關于作用域的問題推薦閱讀《你不知道的JavaScript上卷》第一章(或第一部分),從編譯原理的角度說明什么是作用域。概...
摘要:在中,通過棧的存取方式來管理執行上下文,我們可稱其為執行棧,或函數調用棧。而處于棧頂的是當前正在執行函數的執行上下文,當函數調用完成后,它就會從棧頂被推出理想的情況下,閉包會阻止該操作,閉包后續文章深入詳解。 寫在開篇 已經不敢自稱前端小白,曾經吹過的牛逼總要一點點去實現。 正如前領導說的,自己喝酒吹過的牛皮,跪著都得含著淚去實現。 那么沒有年終完美總結,來個新年莽撞開始可好。 進擊巨...
摘要:此時產生了閉包。導致,函數的活動對象沒有被銷毀。是不是跟你想的不一樣其實,這個例子重點就在函數上,這個函數的第一個參數接受一個函數作為回調函數,這個回調函數并不會立即執行,它會在當前代碼執行完,并在給定的時間后執行。 上一節說了執行上下文,這節咱們就乘勝追擊來搞搞閉包!頭疼的東西讓你不再頭疼! 一、函數也是引用類型的。 function f(){ console.log(not cha...
閱讀 3245·2023-04-26 01:31
閱讀 1892·2023-04-25 22:08
閱讀 3430·2021-09-01 11:42
閱讀 2823·2019-08-30 12:58
閱讀 2165·2019-08-29 18:31
閱讀 2429·2019-08-29 17:18
閱讀 3064·2019-08-29 13:01
閱讀 2551·2019-08-28 18:22