keywords:natives
,array
,object
,function
,RegExp
,date
,error
作為建構器的 Natives
array、object、function、RegExp、Date、Error 使用字面形式來建立這些值,與建構器形式所創建的物件相同,但還是要避免使用建構器,因為有陷阱跟例外
陣列 ( Array )
let a = new Array(4,5,6);
a; // [4,5,6]
let b = [4,5,6];
b; // [4,5,6]
- Array 建構器有一種特殊
( 糟糕 )的使用方法,只有一個 number 引數被傳入建構器不會把該值當作陣列的內容,而是將它當成一個長度來『 預先設定陣列的大小 』 但實際上沒有預設陣列大小這種事情存在,所建立出來的其實是空陣列,只不過該陣列的 length 特性被設定為所指定的數值
看看例子:let a = new Array(3); a.length; // 3 a; // [empty × 3] 可怕的是這在各大不同瀏覽器裡會顯示出不同結果 這裡是 Chrome 的結果 a; // [] (3) = $1 safari 宣告時要使用 var a = new Array(3);
這裡跟之前在 [12]值-陣列、類陣列 時介紹的蠻類似的,如果鍵值 ( key ) 的 string 能被強制轉型為標準的十進位 number ,JavaScript 會假設你想把它當成一個 number 所以來使用,而非作為一個 string 鍵值
let f = []; f['3'] = 99; f.length; // 4 f; // [ empty * 3 , 99 ]
不管在任何情況下,永遠不要刻意建立並使用這種怪異的空插槽陣列,來比較以下三種狀況:
let a = new Array(3); let b = [undefined,undefined,undefined]; let c = []; c.length = 3; a; // [empty × 3] b; // [undefined, undefined, undefined] c; // [empty × 3] delete a[1]; // [empty × 3] delete b[1]; // [undefined, empty, undefined] delete c[1]; // [empty × 3]
Object、Function、RegExp
這些建構器通常也都是非必須的,但 RegExp(..) 具有某些合理的功能:動態地為一個正規表達式定義範式 ( pattern )
let name = 'Eason';
let namePattern = new RegExp("\\b(?:"+name+")+\\b","ig");
'My name is :Eason'.match(namePattern); // ["Eason"]
這種情境常在 JavaScript 中出現,所以會需要使用 new RegExp('pattern','flags') 形式,不過還是強烈建議使用字面值形式定義的正規表達式( regular expressions ),主要的原因是因為效能,JavaScript 引擎會在程式碼執行前預先編譯並快取它們。
Date、Error
這兩個原生建構器有用多了,因為這兩者皆沒有字面值形式可用 XD
Date
要建立一個日期物件值,必須使用 new Date(),此建構器接受額外的引數,以指定使用的日期與時間,若省略就會假設是目前的日期時間
new Date(); // Fri Nov 29 2019 11:18:56 GMT+0800 (台北標準時間) new Date().getTime(); // 1574997536447
- 有一個更簡單的方法,呼叫 ES5 所定義的靜態輔助函式 ( static helper function ): Date.now()
Date.now(); // 1574997536447
- 可以發現呼叫 Date.now(); 會得到跟 new Date().getTime(); 一樣的一串數字,這是該瞬間日期時間的一個字串表示值( string representation )
Error
Error 建構器不管有沒有使用 new 關鍵字,行為都相同
- 一般會想建立錯誤物件主要是將目前的執行堆疊情境( execution stack context )捕捉到該物件中,這個堆疊情境包括了函式呼叫堆疊( function call stack )及錯誤物件建立處的行號,這會使除錯工作容易許多
- 錯誤物件的實體至少會有一個 message 特性,最好在錯誤物件上呼叫 toString() ,以取得經過格式化方便閱讀的錯誤訊息
通常會藉由 throw 運算子來使用錯誤物件
function f1(a) { if (!a) { throw new Error("a wasn't provided"); } ... }
同時可以使用 try…catch 處理錯誤
try { throw new Error('Oops!'); } catch (e) { console.log(e.name + ': ' + e.message); } // Error: Oops!
也可以針對錯誤的型態做不一樣的處理
try { obj.f1(); } catch (e) { if (e instanceof EvalError) { console.log(e.name + ': ' + e.message); } else if (e instanceof RangeError) { console.log(e.name + ': ' + e.message); } ... }