1. 程式人生 > 實用技巧 >Javascript高階之變數、作用域與記憶體

Javascript高階之變數、作用域與記憶體

變數、作用域與記憶體

原始值與引用值

  • 理解要點

    • ECMAScript中所有函式的引數都是按值傳遞的
    • 函式外的值會被複制到函式內部的引數中
    • 關於引用值(物件),也是按值傳遞的
      • 理解
        • 物件中儲存的值是物件的key,也就是指標
        • 函式中按值傳遞時,可以給指標賦值,影響全域性變數
        • 但是改變不了物件的key
        • 可以用物件的動態屬性來理解
  • 確定型別

    • 如果變數是給定引用型別的例項,則instanceof操作符返回true
    • 如果用instanceof檢測原始值,則始終會返回false
let obj= null;
let obj2= {};
let fun= Function.prototype;
let fun2= new Function();
let arr= [];
let str= '';
let reg= new RegExp();
let date= new Date();

console.log(obj instanceof Object);     // false
console.log(obj2 instanceof Object);    // true
console.log(fun instanceof Function);   // false
console.log(fun2 instanceof Function);  // true
console.log(arr instanceof Array);      // true
console.log(str instanceof String);     // false
console.log(reg instanceof RegExp);     // true
console.log(date instanceof Date);      // true

執行上下文與作用域

  • 執行上下文

    • 每個上下文都有一個關聯的變數物件
    • 所有變數和函式都存在於這個物件上
    • 這個物件就是上下文棧,在其所有程式碼執行完畢之後,就會被銷燬
    • var定義的全域性變數和函式,會成為window物件的屬性和方法
  • 作用域鏈

    • 上下文中的程式碼在執行的時候,會建立變數物件的一個作用域鏈
    • 作用域鏈決定了各級上下文中的程式碼在訪問變數和函式時的順序
    • 如果上下文是函式,則其活動物件用作變數物件
    • 活動物件最初只有一個定義變數:arguments
      • arguments是包含函式形參的一個物件
      • 全域性上下文沒有這個變數
  • 作用域鏈增強

    • 在作用域鏈前端新增一個變數物件
      • with語句
        • 會向作用域鏈前端新增指定的物件
      • try/catch語句中的catch塊
        • 會建立一個新的變數物件,這個變數物件會包含要丟擲的錯誤物件的宣告

變數宣告

  • 使用var的函式作用域宣告

    • 變數會被自動新增到最接近的上下文
    • 未宣告的變數,會自動被新增到全域性上下文
    • var宣告會被拿到函式或全域性作用域的頂部,叫做提升
  • 使用let的塊級作用域宣告

    • 塊級作用域由最近的一對包含花括號{}界定
    • let在同一作用域內不能宣告兩次
    • let非常適合在迴圈中宣告迭代變數
  • 使用const的常量宣告

    • const宣告的變數必須同時初始化為某個值
    • const宣告只應用到頂級原語或者物件
    • 使用Object.freeze()
      給物件賦值常量

垃圾回收

  • 標記清理

    • 先給當前不使用的值加上標記,再回來回收它們的記憶體
  • 引用計數

    • 對每個值都記錄它被引用的次數
    • 當引用次數為0時,垃圾回收程式會釋放引用數為0的值的記憶體
  • 迴圈引用

    • 物件A有一個指標指向物件B,而物件B也引用了物件A
    • 只要涉及COM物件,就無法避免迴圈引用的問題

記憶體管理

  • 解除引用

    • 如果資料不再必要,那麼把它設定為null,從而釋放其引用
  • 通過const和let宣告提升效能

    • 塊作用域比函式作用域更早讓垃圾回收程式介入
  • 隱藏類和刪除操作

    • 在建構函式中一次性宣告所有的屬性,因此例項共享隱藏類
    • 把不想要的屬性設定為null,可以保持隱藏類不變和繼續共享
  • 記憶體洩漏

    • 沒有使用關鍵字宣告變數
    • 定時器的回撥通過閉包引用了外部變數
    • 閉包造成的記憶體洩漏
  • 靜態分配和物件池

    • 避免動態分配操作