1. 程式人生 > >js 的初始化順序執行上下文與閉包

js 的初始化順序執行上下文與閉包

  • 1. 程式碼分類(位置)
  •  全域性程式碼
  •  函式(區域性)程式碼
  • 2. 全域性執行上下文
  •  在執行全域性程式碼前將window確定為全域性執行上下文
  •  對全域性資料進行預處理
  •  var定義的全域性變數==>undefined, 新增為window的屬性
  •  function宣告的全域性函式==>賦值(fun), 新增為window的方法
  •  this==>賦值(window)
  •  開始執行全域性程式碼
  • 3. 函式執行上下文
  •  在呼叫函式, 準備執行函式體之前, 建立對應的函式執行上下文物件(虛擬的, 存在於棧中)
  •  對區域性資料進行預處理
  •  形參變數==>賦值(實參)==>新增為執行上下文的屬性
  •  arguments==>賦值(實參列表), 新增為執行上下文的屬性
  •  var定義的區域性變數==>undefined, 新增為執行上下文的屬性
  •  function宣告的函式 ==>賦值(fun), 新增為執行上下文的方法
  • this==>賦值(呼叫函式的物件)
  • 開始執行函式體程式碼
  var a = 3
  function fn () {
    console.log(a)
    var a = 4
  }
  fn()

  console.log(b) //undefined  變數提升
  fn2() //可呼叫  函式提升
  fn3() //不能  變數提升

  var b = 3
  function fn2() {
    console.log('fn2()')
  }

  var fn3 = function () {
    console.log('fn3()')
  }

總結起來就是先全域性上下文,首先是變數提升給undefined值 , 然後是函式提升。放變數和函式提升以後,按序執行程式碼,還有顯式的變數賦值 ,以下程式碼  c 在變數提升,函式提升之後,又經過顯式賦值,最終仍變會number 型別

  var c = 1
  function c(c) {
    console.log(c)
    var c = 3
  }
  c(2) // 報錯

js初始化順序

  • 1. 在全域性程式碼執行前, JS引擎就會建立一個棧來儲存管理所有的執行上下文物件
  • 2. 在全域性執行上下文(window)確定後, 將其新增到棧中(壓棧)
  • 3. 在函式執行上下文建立後, 將其新增到棧中(壓棧)
  • 4. 在當前函式執行完後,將棧頂的物件移除(出棧)
  • 5. 當所有的程式碼執行完後, 棧中只剩下window

閉包

  • 當一個巢狀的內部(子)函式引用了巢狀的外部(父)函式的變數(函式)時, 就產生了閉包

  • 函式巢狀

  • 內部函式引用了外部函式的資料(變數/函式)

  • 1. 使用函式內部的變數在函式執行完後, 仍然存活在記憶體中(延長了區域性變數的生命週期)
  • 2. 讓函式外部可以操作(讀寫)到函式內部的資料(變數/函式)
  •  
  • 問題:
  • 1. 函式執行完後, 函式內部宣告的區域性變數是否還存在? 一般是不存在, 存在於閉中的變數才可能存在
  • 2. 在函式外部能直接訪問函式內部的區域性變數嗎? 不能, 但我們可以通過閉包讓外部操作它
  • 1. 產生: 在巢狀內部函式定義執行完時就產生了(不是在呼叫)
  • 2. 死亡: 在巢狀的內部函式成為垃圾物件時
    function fn1() {
      //此時閉包就已經產生了(函式提升, 內部函式物件已經建立了)
      var a = 2
      function fn2 () {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f() // 3
    f() // 4
    f = null //閉包死亡(包含閉包的函式物件成為垃圾物件)