【JS高階程式設計(第4版)學習筆記】第四章 變數、作用域與記憶體
4.1 原始值與引用值
ECMAScript變數可以包含兩種不同型別的資料:原始值和引用值。原始值就是最簡單的資料,引用值則是由多個值構成的物件。
在操作物件時,實際上操作的是對該物件的引用而非實際的物件本身。因此,儲存引用值的變數是按引用訪問的。
4.1.1 動態屬性
原始值和引用值的定義方式很類似,都是建立一個變數,然後給它賦值。對於引用值而言,可以隨時新增、修改和刪除其屬性和方法。
let person = new Object(); person.name = "Nicholas"; console.log(person.name); // "Nicholas"
原始值不能有屬性,儘管嘗試給原始值新增屬性不會報錯
let name = "Nicholas"; name.age = 27; console.log(name.age); // undefined
原始型別的初始化可以只使用原始字面量形式。如果使用的是new關鍵字,則JavaScript會建立一個Object型別的例項,但其行為類似原始值
let name1 = "Nicholas"; let name2 = new String("Matt"); name1.age = 27; name2.age = 26; console.log(name1.age); // undefined console.log(name2.age); // 26 console.log(typeofname1); // string console.log(typeof name2); // object
4.1.2 複製值
原始值和引用值在通過變數複製時也有所不同。在通過變數把一個原始值賦值到另一個變數時,原始值會被複制到新變數的位置。(這兩個變數可以獨立使用,互不干擾)
在把引用值從一個變數賦給另一個變數時,儲存在變數中的值也會被複制到新變數所在的位置。區別在於,這裡複製的值實際上是一個指標,它指向儲存在堆記憶體中的物件。操作完成後,兩個變數實際上指向同一個物件。
let obj1 = new Object(); let obj2 = obj1; obj1.name = "Nicholas"; console.log(obj2.name);// "Nicholas"
4.1.3 傳遞引數
ECMAScript中所有函式的引數都是按值傳遞的。這意味著函式外的值會被複制到函式內部的引數中,就像從一個變數複製到另一個變數一樣。如果是原始值,那麼就跟原始值,那麼就跟原始值變數的複製一樣。如果是引用值,那麼就跟引用值變數的複製一樣。
function addTen(num) { num += 10; return num; } let count = 20; let result = addTen(count); console.log(count); // 20,沒有變化 console.log(result); // 30
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"
注意 ECMAScript 中函式的引數就是區域性變數。
4.1.4 確定型別
typeof操作符最適合用來判斷一個變數是否為原始型別。它可以判斷變數是否為字串、數值、布林值或undefined的最好方式。如果值是物件或null,那麼typeof返回“object”
let s = "Nicholas"; let b = true; let i = 22; let u; let n = null; let o = new Object(); console.log(typeof s); // string console.log(typeof i); // number console.log(typeof b); // boolean console.log(typeof u); // undefined console.log(typeof n); // object console.log(typeof o); // object
instanceof操作符可以知道引用值是什麼型別的物件:result=variable instanceof constructor
console.log(person instanceof Object); // 變數 person 是 Object 嗎? console.log(colors instanceof Array); // 變數 colors 是 Array 嗎? console.log(pattern instanceof RegExp); // 變數 pattern 是 RegExp 嗎?
所有引用值都是 Object 的例項,因此通過 instanceof 操作符檢測任何引用值和Object 建構函式都會返回 true 。類似地,如果用 instanceof 檢測原始值,則始終會返回 false ,
4.2 執行上下文與作用域
執行上下文(簡稱"上下文")的概念在JavaScript中是頗為重要的。變數或函式的上下文決定了它們可以訪問哪些資料,以及它們的行為。上下文中的程式碼在執行的時候,會建立變數物件的一個作用域。這個作用域鏈決定了各級上下文中的程式碼在訪問變數和函式時的順序。
簡而言之,執行上下文就是有一個變數在哪裡可以訪問在哪裡不能訪問。
4.3 垃圾回收
JavaScript通過自動記憶體管理實現記憶體分配和閒置資源回收。基本思路:確定哪個變數不會再使用然後釋放它佔用的記憶體。這個過程是週期性的,即垃圾回收程式每隔一定時間(或者說在程式碼執行過程中某個預定的收集時間)就會自動執行。