JS之函數相關

函數概述

  • 定義: 封裝一項專門任務的步驟清單的代碼段, 並起一個名字
  • 何時使用函數
    • 當一項任務需要反覆執行, 但又不希望重複編寫時
  • 函數: 封裝函數定義的引用類型對象
  • 函數名: 指向函數定義的一個變量
  • 聲明時不執行, 也不讀取內部的代碼, 調用時纔讀取內部代碼並執行
  • 聲明提前: 正式開始執行程序前, 先將var聲明的變量和function聲明的函數提前到當前作用域的頂部, 集中聲明, 賦值留在原地。
  • 按值傳遞: 兩變量間賦值, 或將變量作爲函數的參數傳遞時, 都僅將變量中的值copy一份給對方。
  • 全局函數: 在ES標準中規定的, 由瀏覽器廠商實現的。不需要任何對象前綴就可以直接訪問的函數
    • 編碼解碼
      • 問題1: url中不允許出現多字節字符
        • 解決: 使用encodeURI(), 將多字節字符編碼爲utf-8格式的單字節字符
        • 使用decodeURI(), 將收到的編碼後的單字節字符, 解碼爲多字節字符原文
      • 問題2: url中不允許出現url的保留字符
        • 解決: 使用encodeURIComponent(), 編碼多字節字符和保留字
        • 使用decodeURLComponent()解碼
    • eval: 執行字符串格式的語句或表達式
      • 如eval(“alert(‘Hello’)”)
    • JS中分母是0, 不報錯, 返回infinity。分子與分母同時爲0, 返回NaN。

函數對象

  • 執行環境棧(ECS, Execution Context Stack): 保存全局以及每個函數的執行環境的棧結構
  • 執行環境(EC): 調用函數時, 創建的引用函數資源的對象
  • 變量對象(VO, Variable Object): 專門存儲變量的對象
  • 瀏覽器打開時的內存邏輯: 窗口一打開, 默認ESC中壓入一個全局EC, 全局EC引用了window對象的VO
  • 注意: window中的變量都是全局變量
  • 活動對象(AO, Activation Object):專門保存本次函數調用時的局部變量, AO中有一個屬性始終指向window對象

函數的生命週期

  1. 定義時: 僅創建一個函數對象, 封裝了函數定義, 不會讀取函數的內容
  2. 調用時: 創建函數的EC對象壓入ECS中, 函數的EC對象引用了當前函數的AO
    • 變量的使用規則: 優先在AO中找, 找不到, 再去window對象中找
  3. 調用後: 函數的EC對象出棧, AO對象失去引用, 被回收, AO對象的局部變量一起被釋放

函數重載

  • 重載: 程序中同時定義多個相同函數名, 不同函數列表的函數。調用時, 根據傳入參數的不同, 動態選擇匹配的函數執行。
  • 注意: JS語法不支持重載, 可使用arguments實現重載效果。
  • 何時使用重載: 不同參數, 不同操作, 但操作名稱相同
  • 使用重載的目的: 減輕調用者調用時選擇的負擔
  • arguments: 所有函數對象中默認都有的專門接收調用時傳入參數的值的類數組對象。
  • 類數組對象: 類似於數組的對象
    • 類數組對象與數組的相同點
      • arguments.length: 參數值的個數
      • arguments[i]: 獲得下標爲i位置的參數值
  • 參數變量: 提醒調用者, 如何正確使用函數

如何創建函數對象

  • 聲明方式: function 函數名(參數列表){函數體; return 值;}
    • 只有聲明方式才能被提前
  • 函數直接量:
    • var 函數名 = function(參數列表){函數體; return 值;}
  • new function:
    • var 函數名 = new function(“參數1”, “參數2”,…”函數體”);

匿名函數

  • 定義: 定義時沒有變量引用
  • 何時使用:
    • 匿名函數自調: 定義完立刻執行, 執行完立刻釋放
      • 何時使用自調: 一個函數只用一次
      • 使用方法:
        • (function(參數列表){})(參數值列表)
        • (functiuon(參數列表){}(參數值列表))
    • 回調: 將函數作爲對象傳遞給其他函數, 由其他函數調用
      • 何時使用回調: 如果一個函數只能被另一個函數調用
  • 優點: 節省內存空間
  • 缺點: 無法反覆使用

作用域與作用域鏈

  • 作用域: 一個變量的可用範圍, 其實就是變量的實際存儲位置
    • 本質: EC對象的一個scope屬性, 引用了window或AO
      • window: 全局作用域 —— 全局變量
      • AO: 局部作用域 —— 局部變量
  • 作用域鏈: 以當前EC的scope屬性爲起點依次向上引用每個AO, 直到window結束, 形成的多級引用關係, 只要是在作用域鏈上存在的變量, 當前函數都可使用

閉包

  • Problem: 全局變量, 在程序任何位置都可訪問(修改), 這樣會造成全局污染。但是局部變量又不可重用。
  • 解決方案: 既要重用變量, 又要保護變量不被污染 —— 閉包
  • 如何創建閉包:
    1. 先用外層函數封裝一個受保護的局部變量
    2. 再用內層函數操作外層函數的變量
    3. 外層函數將內層函數返回到外部, 在外部反覆調用
  • 如何判斷一個閉包:
    • 函數嵌套
    • 內層函數使用外層函數的變量
    • 內層函數被返回到外部, 在外部調用
  • 何時使用閉包: 既要重用變量, 又要保護變量不被污染
  • 缺點: 佔用更多的內存空間, 因爲outer的活動對象無法釋放
  • 判斷閉包輸出
    • 同一次外層函數調用返回的內層函數, 操作同一個變量
    • 外層函數調用了幾次就有幾個受保護的變量副本
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章