執行上下文
1. 代碼分類(位置)
* 全局代碼
* 函數(局部)代碼
2. 全局執行上下文
* 在執行全局代碼前將window確定為全局執行上下文
* 對全局數據進行預處理
* var定義的全局變量==>undefined, 添加為window的屬性
* function聲明的全局函數==>賦值(fun), 添加為window的方法
* this==>賦值(window)
* 開始執行全局代碼 //
3. 函數執行上下文
* 在調用函數, 准備執行函數體之前, 創建對應的函數執行上下文對象(虛擬的, 存在於棧中)
* 對局部數據進行預處理
* 形參變量==>賦值(實參)==>添加為執行上下文的屬性
* arguments==>賦值(實參列表), 添加為執行上下文的屬性
* var定義的局部變量==>undefined, 添加為執行上下文的屬性
* function聲明的函數 ==>賦值(fun), 添加為執行上下文的方法
* this==>賦值(調用函數的對象)
* 開始執行函數體代碼
4執行上下文棧
1. 在全局代碼執行前, JS引擎就會創建一個棧來存儲管理所有的執行上下文對象
2. 在全局執行上下文(window)確定后, 將其添加到棧中(壓棧)
3. 在函數執行上下文創建后, 將其添加到棧中(壓棧)
4. 在當前函數執行完后,將棧頂的對象移除(出棧)
5. 當所有的代碼執行完后, 棧中只剩下window
5:面試題目
/*
測試題1: 先執行變量提升, 再執行函數提升
*/
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 等價於 var a ,function c() ,變量提前-》函數提前,最后賦值
function c(c) {
console.log(c)
var c = 3
} c=1,C是一個數值不是函數對象
c(2) // 報錯
//面試題:
Funcution fun(){ var a=b=3; }
Console.log(b)//B是全局變量 var a是局部變量 B=3;A=undefine
6:作用域和作用域鏈
1. 理解
* 就是一塊"地盤", 一個代碼段所在的區域
* 它是靜態的(相對於上下文對象), 在編寫代碼時就確定了
2. 分類
* 全局作用域
* 函數作用域
* 沒有塊作用域(ES6有了)
3. 作用
* 隔離變量,不同作用域下同名變量不會有沖突
1. 區別1
* 全局作用域之外,每個函數都會創建自己的作用域,作用域在函數定義時就已經確定了。而不是在函數調用時
* 全局執行上下文環境是在全局作用域確定之后, js代碼馬上執行之前創建
* 函數執行上下文是在調用函數時, 函數體代碼執行之前創建
2. 區別2
* 作用域是靜態的, 只要函數定義好了就一直存在, 且不會再變化
* 執行上下文是動態的, 調用函數時創建, 函數調用結束時就會自動釋放
3. 聯系
* 執行上下文(對象)是從屬於所在的作用域
* 全局上下文環境==>全局作用域
* 函數上下文環境==>對應的函數使用域
1. 理解
* 多個上下級關系的作用域形成的鏈, 它的方向是從下向上的(從內到外)
* 查找變量時就是沿着作用域鏈來查找的
2. 查找一個變量的查找規則
* 在當前作用域下的執行上下文中查找對應的屬性, 如果有直接返回, 否則進入2
* 在上一級作用域的執行上下文中查找對應的屬性, 如果有直接返回, 否則進入3
* 再次執行2的相同操作, 直到全局作用域, 如果還找不到就拋出找不到的異常
-->
<script type="text/javascript">
var a = 1
function fn1() {
var b = 2
function fn2() {
var c = 3
console.log(c)
console.log(b)
console.log(a)
console.log(d)
}
fn2()
}
fn1()
</script>
3:面試題 X=10
///2
var fn = function () {
console.log(fn)
}
fn()
var obj = {
fn2: function () {
console.log(fn2)
//console.log(this.fn2)
}
}
obj.fn2()