在前端領域,功能再怎麼強大好用的框架,終究使用 JavaScript 來建構出來的,所以在使用上對於 JavaScript 一定要有一定程度的掌握才行。
本篇不講語法的部分,語法到 MDN 等網站可以有更詳盡的說明與範例,這邊就來分享一下我在學習 JavaScript 時,感到比較容易讓人混淆的一些觀念。
所有 物件 都是 物件型別(Object Type) ,除了以下 6 種 原始型別:
所以產生了一個有趣的特性,在 JS 中 function
也是物件,這也是為什麼 function
可以被作為參數傳入其他 function
,也是 JS 賴以實現物件導向開發的重要特性。
var obj = {};
obj.name = '物件';
obj.foo = () => 'OK';
obj.name; //物件
obj.foo; //() => 'OK'
obj.foo(); //OK
若是一樣的步驟,可是宣告的是原始型別呢?
var str = '字串';
str.name = '原始型別';
str.foo = () => 'OK';
str.name; //undefined
str.foo; //undefined
str.foo(); //Uncaught TypeError: str.foo is not a function
當我們試圖讀取一個物件的屬性時,若物件沒有該屬性,則會透過原型鍊不斷往上查找,就如同變數會向外查找一般。
因此若我們在 Array
物件上定義了一個方法:
Array.prototype.hahaha = () => console.log('hahaha')
那麼就會讓所有的 Array 物件都具備這個方法。
var arr = [];
arr.hahaha(); // hahaha
宣告的變數或定義的屬性,代表的都只是一組記憶體位置的指標,實際上的內容就儲存在該位置。
在使用 =
進行 賦值 的當下,系統會在記憶體中建立一個容器,而變數及屬性紀錄的就是該容器的記憶體位址。
但是,若將變數賦值給另一個變數時,會有容易讓人混淆的部分,例如:
var num1 = 1;
var num2 = num1;
num2 === num1; //true
num1++;
num2 === num1; //false
上面這段看起來很合理,但是如果改成物件呢?
var obj1 = {};
var obj2 = obj1;
obj2 === obj1; //true
obj1.num = 1;
obj2.num; //1
var let const function
都帶有 Hoisting 提升的特性
var
的 Hoisting 只會提升 宣告 本身,不提升賦值
function
的 Hoisting 會將整個 function 提升
let const
的 Hoisting 不提升宣告也不提升賦值
透過 var
宣告的變數,作用範圍是以 function 為單位。
透過 let const
宣告的變數,作用範圍是以 Block 為單位。
全域宣告下的變數或 function
,會成為全域物件(window)的 屬性
...雖然沒宣告的也會。
而在 function 中宣告的變數,則不會成為任何物件的屬性,僅會在執行階段使用,當執行環境終結時,變數則回收銷毀。
但有趣的是,雖然變數銷毀了,但記憶體中的內容卻是會依照狀況被保留的。
這個特性就是「閉包」的基礎。
閉包的範例:
function a(num){
return () => num++
}
var na = new a(0);
na(); // 1
na(); // 2
na(); // 3