1. 程式人生 > 其它 >變數提升+函式提升+執行上下文

變數提升+函式提升+執行上下文

210310

一、變數宣告提升
  • 通過var定義(宣告)的變數,在定義語句之前就可以訪問到
  • 值:undefined
二、函式宣告提升
  • 通過function宣告的函式,在之前就可以直接呼叫
  • 值:函式定義(物件)
var a = 3
function fn(){
    /*相當於先聲明瞭a var a;a = undefined
    先在自身函式中找變數,再去全域性找
    */
    console.log(a) //undefined
    var a = 4
}
fn()  //undefined

console.log(b) //undefined //變數提升
fn2() //可呼叫 函式提升
fn3() //變數提升,不可執行
var b = 3
function fn2(){
    console.log('fn2')
}
var fn3 = function(){
    console.log('fn3')
}

注意:
先執行變數提升,在執行函式提升(函式優先順序更高:函式提升晚,會覆蓋相同變數名的變數提升)
測試一:

function a(){}
var a
console.log(typeof a)  //function

測試二:

var c = 1  //=>①var c
function c(c){
    console.log(c)
    var c = 3  //無關
}
//=>②c = 1 =>c typeof number
c(2) //報錯c is not a function
三、執行上下文
  1. 程式碼分類(位置)

    • 全域性程式碼
    • 函式(區域性)程式碼
  2. 全域性執行上下文

    • 在執行全域性程式碼前將window確定為全域性執行上下文

    • 對全域性資料進行預處理(收集資料)

      • var定義的全域性變數==>(初始化賦值)undefined,新增為window的屬性
      • function宣告的全域性函式==>賦值(函式物件),新增為window的方法
      • this==>賦值(window)
    • 開始執行全域性程式碼

      c = 3 //特殊:未執行語句之前,window中不包含此變數,需用var定義
      console.log(a1,window.a1) //undefined
      a2() //a2()
      console.log(this) //window
      var a1 = 2
      function a2(){
          console.log('a2()')
      }
      console.log(a1) //2
      
  3. 函式執行上下文

    • 在呼叫函式,準備執行函式體之前,建立對應的函式執行上下文物件(虛擬的,存在於棧中)

    • 對區域性資料進行預處理

      • 形參變數>賦值(實參)>新增為執行上下文的屬性
      • arguments==>賦值(實參列表),新增為執行上下文的屬性
      • var定義的區域性變數==>undefined,新增為執行上下文的屬性
      • function宣告的函式==>賦值(函式物件),新增為執行上下文的方法
      • this==>賦值(呼叫函式的物件)
    • 開始執行函式體程式碼

      function f1(a1){
          console.log(a1)
          console.log(a2)
          a3()
          console.log(this)
          console.log(arguments)
          
          var a2 = 3
          function a3(){
              console.log('a3()')
          }
      }
      f1(2,3) //2,undefined,a3(),window,2 3
      

210314執行上下文棧

  1. 在全域性程式碼執行前,js引擎就會建立一個棧來儲存管理所有的執行上下文物件
  2. 在全域性執行上下文(window)確定後,將其新增到棧中(壓棧)
  3. 在函式執行上下文建立後,將其新增到棧中(壓棧)
  4. 在當前函式執行完後,將棧頂的物件移出(出棧)
  5. 當所有的程式碼執行完畢,棧中只剩下window
//呼叫一次函式產生一次執行上下文棧n+1(window)
//1、進入window全域性執行上下文
var a = 10
var bar = function(x){
    var b = 5
    //2、進入foo執行上下文
    foo(x + b)
}
var foo = function(y){
    var c = 5
    console.log(a + c + y)
}
//3、進入bar函式執行上下文
bar(10)  //30
console.log('global begin:' + i)
var i = 1
foo(1)
function foo(i){
    if(i == 4){
        return
    }
    console.log('foo() begin:' + i)
    foo(i + 1)//遞迴呼叫:在函式內部呼叫自己
    console.log('foo() end:' + i)
}
console.log('global end:' + i)
/*函式依次輸出:
global begin:undefined
foo() begin:1
foo() begin:2
foo() begin:3
foo() end:3
foo() end:2
foo() end:1
global end:1
整個過程中產生了五個執行上下文
*/