【JavaScript高階】6、函式高階(執行上下文與執行上下文棧)
阿新 • • 發佈:2019-01-01
一、變數提升與函式提升
1. 變數宣告提升 * 通過var定義(宣告)的變數, 在定義語句之前就可以訪問到 * 值: undefined 2. 函式宣告提升 * 通過function宣告的函式, 在之前就可以直接呼叫 * 值: 函式定義(物件) 3. 問題: 變數提升和函式提升是如何產生的?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>01_變數提升與函式提升</title> </head> <body> <script type="text/javascript"> console.log('-----') /* 面試題 : 輸出 undefined */ var a = 3 function fn () { console.log(a) // undefined var a = 4 } fn() console.log(b) //undefined 變數提升 fn2() //可呼叫 函式提升 // fn3() //不能 變數提升 var b = 3 function fn2() { console.log('fn2()') // fn2() } var fn3 = function () { console.log('fn3()') } </script> </body> </html>
二、執行上下文
1. 程式碼分類(位置) * 全域性程式碼 * 函式(區域性)程式碼 2. 全域性執行上下文 * 在執行全域性程式碼前將window確定為全域性執行上下文 * 對全域性資料進行預處理 * var定義的全域性變數==>undefined, 新增為window的屬性 * function宣告的全域性函式==>賦值(fun), 新增為window的方法 * this==>賦值(window) * 開始執行全域性程式碼 3. 函式執行上下文 * 在呼叫函式, 準備執行函式體之前, 建立對應的函式執行上下文物件(虛擬的, 存在於棧中) * 對區域性資料進行預處理 * 形參變數==>賦值(實參)==>新增為執行上下文的屬性 * arguments==>賦值(實參列表), 新增為執行上下文的屬性 * var定義的區域性變數==>undefined, 新增為執行上下文的屬性 * function宣告的函式 ==>賦值(fun), 新增為執行上下文的方法 * this==>賦值(呼叫函式的物件) * 開始執行函式體程式碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>02_執行上下文</title> </head> <body> <script type="text/javascript"> //全域性執行上下文 console.log(a1,window.a1) // undefined undefined window.a2() // 'a2()' console.log(this) // window var a1 = 10 function a2() { console.log('a2()') } console.log(a1) // 10 console.log('----------------------') //函式執行上下文 function fn(a1) { console.log(a1) // 2 console.log(a2) // undefined a3() // 'a3()' console.log(this) // window console.log(arguments) // 2 3 var a2 = 3 function a3() { console.log('a3()') } } fn(2,3) </script> </body> </html>
三、執行上下文棧
1. 在全域性程式碼執行前, JS引擎就會建立一個棧來儲存管理所有的執行上下文物件 2. 在全域性執行上下文(window)確定後, 將其新增到棧中(壓棧) 3. 在函式執行上下文建立後, 將其新增到棧中(壓棧) 4. 在當前函式執行完後,將棧頂的物件移除(出棧) 5. 當所有的程式碼執行完後, 棧中只剩下window
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_執行上下文棧</title>
</head>
<body>
<script type="text/javascript">
var a = 10
var bar = function (x) {
var b = 5
foo(x + b)
}
var foo = function (y) {
var c = 5
console.log(a + c + y) // 10+5+15=30
}
bar(10)
</script>
</body>
</html>
四、執行上下文棧2
1. 依次輸出什麼? gb: undefined fb: 1 fb: 2 fb: 3 fe: 3 fe: 2 fe: 1 ge: 1 2. 整個過程中產生了幾個執行上下文? 5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_執行上下文棧2</title>
</head>
<body>
<script type="text/javascript">
console.log('gb: '+ i) // gb:undefined
var i = 1
foo(1) // fb:1 fb:2 fb:3 fe:3 fe:2 fe:1 ge:1 全域性入棧一次,呼叫函式入棧四次,總共五次執行上下文
function foo(i) {
if (i == 4) {
return
}
console.log('fb:' + i)
foo(i + 1) //遞迴呼叫: 在函式內部呼叫自己
console.log('fe:' + i)
}
console.log('ge: ' + i)
</script>
</body>
</html>
五、面試題
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_面試題</title>
<style>
</style>
</head>
<body>
<div style=""></div>
<script type="text/javascript">
/*
測試題1: 先執行變數提升, 再執行函式提升
*/
function a() {}
var a
console.log(typeof a) // 'function'
/*
測試題2:
*/
if (!(b in window)) { // 全域性b變數提升存在,所以執行不了if內語句
var b = 1
}
console.log(b) // undefined
/*
測試題3:
*/
var c = 1
function c(c) {
console.log(c)
var c = 3
}
//c(2) // c(2)會報錯,前面變數提升完,這裡c賦值為1,所以c不是函式無法呼叫
</script>
</body>
</html>