JavaScript高階程式設計筆記 - 第四章 變數 作用域 記憶體問題

完顏阿骨折發表於2019-01-09

4.1 基本型別和引用型別的值

  • 基本型別: 簡單的資料段
  • 引用型別: 指那些可能有多個值構成的物件, 指儲存在記憶體中的物件

4.1.2 複製變數值

  • 除了儲存的方式不同之外,在從一個變數向另一個變數複製基本型別值和引用型別值時,也存在不同
  1. 基本型別: 如果從一個變數向另一個變數複製基本型別的值,會在變數物件上建立一個新值,然後把該值複製到為新變數分配的位置上

    基本型別複製

  2. 引用型別: 當從一個變數向另一個變數複製引用型別的值時,同樣也會將儲存在變數物件中的值複製一份放到為新變數分配的空間中。不同的是,這個值的副本實際上是一個指標,而這個指標指向儲存在堆中的一 個物件。複製操作結束後,兩個變數實際上將引用同一個物件。因此,改變其中一個變數,就會影響另 一個變數

    引用型別複製

4.1.3 傳遞引數

  • 傳遞基本型別
    function addTen(num) {
        num += 10
        return num;
    }
    var count = 20
    var result = addTen(count)
    console.log(count) // 20, 沒有變化
    console.log(result) // 30
複製程式碼
  • 傳遞引用型別
    function setName(obj) {
        obj.name = "Nicholas"
    }
    var person = new Object()
    setName(person);
    console.log(person.name) // "Nicholas"
複製程式碼
    // 為了證明物件是按值傳遞的
    function setName(obj) {
        obj.name = "Nicholas"
        obj = new Object()
        obj.name = "Greg"
    }
    var person = new Object()
    setName(person);
    console.log(person.name) // "Nicholas"
複製程式碼

4.1.4 檢測型別

  • typeof: 檢測基本資料型別, string, number, boolean, undefined,object(物件, null)
  • instanceof: 檢測引用型別, 什麼型別的物件, 所有引用型別的值都是 Object 的例項

4.2 執行環境及作用域

  • 執行環境定義了**函式和變數有權訪問的其他資料, 每個執行環境都有與之對應的變數物件**, 環境中定義的變數和函式都定義在這個物件中
  • 全域性環境是最外層的執行環境, 在web瀏覽器中被認為是**windows**物件,因為所有的全域性變數和函式都作為window 物件的屬性和方法,執行環境中的程式碼執行完畢後,該環境被銷燬,其中的所有變數和函式定義也隨之銷燬
  • 每個函式都有自己的執行環境, 當執行流進入某個函式時, 函式的執行環境就會就會進入環境棧, 函式執行完畢後,環境出棧, 把控制權交給之前的執行環境
  • 當程式碼在某個環境中執行, 會建立變數物件的**作用域鏈, 作用域鏈保證對執行環境有權訪問的所有變數和函式的有序訪問, 作用域鏈的前端始終是當前執行環境的變數物件,最後一個物件是全域性環境中的變數物件**, 如果這個環境是函式,則將其活動物件作為變數物件. 活動物件最開始只包含arguments物件(全域性環境不存在)
    var color = 'blue'
    function changeColor() {
        if (color === 'blue') {
            color = 'red'
        } else {
            color = 'blue'
        }
    }
    changeColor()
    console.log(color)
    
    // changeColor() 函式中包含自己的變數物件和全域性環境的變數物件
複製程式碼
        var color = "blue";
        function changeColor(){
            var anotherColor = "red";
            function swapColors(){
                var tempColor = anotherColor;
                anotherColor = color;
                color = tempColor;
                    // 這裡可以訪問color、anotherColor和tempColor 
        }
            // 這裡可以訪問color和anotherColor,但不能訪問tempColor
            swapColors();
    }
    // 這裡只能訪問color 
    changeColor();
複製程式碼

函式的作用域鏈圖

JavaScript高階程式設計筆記 - 第四章 變數 作用域 記憶體問題

4.2.1 延長作用域鏈

當執行流進入下列任何一個語句時,作用域鏈就會得到加長:

  • try-catch語句的catch塊
  • with語句

這兩個語句都會在作用域鏈的前端新增一個變數物件,對with語句來說,會將指定的物件新增到作用域鏈中.對catch語句來說,會建立一個新的變數物件,其中包含的是被丟擲的錯誤物件的宣告

4.2.2 沒有塊級作用域

javascript沒有塊級作用域

    if (true) {
        var color = "blue"
    }
    console.log(color) // blue
    // javascript中, if 語句中的變數宣告會將變數新增到當前的執行環境中
複製程式碼
    function func() {
        if (true) {
            var color = "blue"
        }
        console.log(color) 
    }
    func() // blue
    console.log(color) // error
    // color 新增到了func執行環境中,並沒有新增到window執行環境中
複製程式碼
    for (var i = 0; i < 10; i++) {
        ......
    }
    console.log(i) // 10
複製程式碼
  • 宣告變數 var 宣告的變數會被新增到最近的環境中,在**函式內部就是最近的環境就是區域性環境; 在with語句中就是函式環境, 如果初始化變數沒有使用var則被新增到全域性環境**中
    function add(num1, num2) {
        var sum = num1 + num2
        return sum
    }
    var result = add(10, 20) // 30
    console.log(sum) // error
複製程式碼
    function add(num1, num2) {
        sum = num1 + num2
        return sum
    }
    var result = add(10, 20) // 30
    console.log(sum) // 30
複製程式碼
  • 識別符號查詢 在某個環境中為了讀取或者寫入而引入一個識別符號,必須通過搜尋來確定該識別符號的意思, 搜尋過程從當前作用域前端開始逐步向上查詢直至全域性作用域為止
    var color = 'blue'
    function getColor() {
        return color
    }
    console.log(getColor()) // 'blue'
複製程式碼

搜尋過程如下

搜尋過程如下

相關文章