為了能很好的認識“上下文”是什么東西型型。我們來看幾個例子。
小明告訴小紅:“你放心吧犹菇,他答應你的條件了德迹。”
在讀者的眼中我們不知道小明說的他是指的誰揭芍,但是如果加上一句話胳搞、
從小強家里出來后,小明告訴小紅:“你放心吧称杨,他答應你的條件了肌毅。”
這個時候我們都知道他指的是誰了姑原。我們以JavaScript為例子
// 如果只看這個函數悬而,誰都無法確認 `this` 是誰,因為缺乏“上下文”
function someFunction() {
console.log(this.xxx)
}
// 解釋器在此情形下會將 `this` 視作 `window` 對象(瀏覽器中)
// 由于 `window.xxx` 并不存在锭汛,所以會輸出 `undefined`
someFunction() // undefined
// 然而笨奠,一些方法可以幫助我們指明“上下文”,于是就不會含糊不清唤殴;比如:
var test = { xxx: 'hello' }
someFunction.call(test) // "hello"
以下就為尚硅谷的JavaScript進階筆記了般婆。
1.代碼分類(位置)
- 全局代碼
- 函數(局部)代碼
2.全局執(zhí)行上下文
在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文
-
對全局數據進行預處理
- var定義的全局變量==>undefined, 添加為window的屬性
- function聲明的全局函數==>賦值(fun), 添加為window的方法
- this==>賦值(window)
開始執(zhí)行全局代碼
3.函數執(zhí)行上下文
- 在調用函數, 準備執(zhí)行函數體之前, 創(chuàng)建對應的函數執(zhí)行上下文對象(虛擬的, 存在于棧中)
- 對局部數據進行預處理
- 形參變量==>賦值(實參)==>添加為執(zhí)行上下文的屬性
- arguments==>賦值(實參列表), 添加為執(zhí)行上下文的屬性
- var定義的局部變量==>undefined, 添加為執(zhí)行上下文的屬性
- function聲明的函數 ==>賦值(fun), 添加為執(zhí)行上下文的方法
- this==>賦值(調用函數的對象)
- 開始執(zhí)行函數體代碼
- 在全局代碼執(zhí)行前, JS引擎就會創(chuàng)建一個棧來存儲管理所有的執(zhí)行上 下文對象
- 在全局執(zhí)行上下文(window)確定后, 將其添加到棧中(壓棧)
- 在函數執(zhí)行上下文創(chuàng)建后, 將其添加到棧中(壓棧)
- 在當前函數執(zhí)行完后,將棧頂的對象移除(出棧)
- 當所有的代碼執(zhí)行完后, 棧中只剩下window
注:圖在JavaScript高級教程中有
例:以下代碼 依次輸出什么? 整個過程中產生了幾個執(zhí)行上下文?
console.log('gb: '+ i)
var i = 1
foo(1)
function foo(i) {
if (i == 4) {
return
}
console.log('fb:' + i)
foo(i + 1) //遞歸調用: 在函數內部調用自己
console.log('fe:' + i)
}
console.log('ge: ' + i)
依次輸出 gb: undefined
fb: 1
fb: 2
fb: 3
fe: 3
fe: 2
fe: 1
ge: 1一共產生了5個上下文對象
一些測試題目
/*
測試題1: 先執(zhí)行變量提升, 再執(zhí)行函數提升
*/
function a() {}
var a
console.log(typeof a) // 'function'
/*
測試題2:
*/
if (!(b in window)) {
var b = 1
}
console.log(b) // undefined
/*
測試題3:
*/
var c = 1
function c(c) {
console.log(c)
var c = 3
}
c(2) // 報錯
關于測試題3的執(zhí)行步驟是:
var c //先執(zhí)行了變量提升
function c(c){ // 后面進行了函數提升
console.log(c)
var c=3
}
c=1 // 這里給c賦值了朵逝,則c存儲了1
c(2) // 當然c不再是一個函數就報錯了蔚袍。