JavaScript 型別檢查 (typeof / instanceof)
JavaScript 是動態型別語言,變數的型別可以在執行時改變。本篇介紹如何檢查值的型別。
typeof 運算子
typeof 運算子回傳一個字串,表示運算元的型別:
typeof 123; // 'number'
typeof 'hello'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Symbol(); // 'symbol'
typeof 123n; // 'bigint'
typeof function() {}; // 'function'
typeof {}; // 'object'
typeof []; // 'object'
typeof null; // 'object' (歷史遺留的 bug)
typeof 的回傳值
| 型別 | typeof 結果 |
|---|---|
| Number | 'number' |
| String | 'string' |
| Boolean | 'boolean' |
| Undefined | 'undefined' |
| Symbol | 'symbol' |
| BigInt | 'bigint' |
| Function | 'function' |
| 其他物件(含 Array、null) | 'object' |
typeof 的用途
檢查變數是否已定義
// 安全地檢查變數是否存在
if (typeof myVar !== 'undefined') {
// myVar 已定義
}
// 直接使用可能會報錯
if (myVar !== undefined) { // ReferenceError(如果 myVar 未宣告)
}
檢查基本型別
function processValue(value) {
if (typeof value === 'string') {
return value.toUpperCase();
} else if (typeof value === 'number') {
return value * 2;
} else if (typeof value === 'boolean') {
return !value;
}
}
typeof 的陷阱
null 的問題
typeof null; // 'object'(這是 JavaScript 的歷史 bug)
// 正確檢查 null
var value = null;
if (value === null) {
console.log('是 null');
}
無法區分物件類型
typeof {}; // 'object'
typeof []; // 'object'
typeof new Date(); // 'object'
typeof /regex/; // 'object'
// typeof 無法區分這些不同的物件類型
instanceof 運算子
instanceof 用來檢查物件是否是某個建構函式的實例(檢查原型鏈):
var arr = [1, 2, 3];
var obj = { a: 1 };
var date = new Date();
arr instanceof Array; // true
arr instanceof Object; // true(Array 也繼承自 Object)
obj instanceof Object; // true
date instanceof Date; // true
date instanceof Object; // true
自訂建構函式
function Person(name) {
this.name = name;
}
var mike = new Person('Mike');
mike instanceof Person; // true
mike instanceof Object; // true
instanceof 的限制
跨 frame/window 失效
在瀏覽器中,不同 frame 或 window 的 Array 是不同的建構函式:
// 從 iframe 取得的陣列
var iframeArray = iframe.contentWindow.Array;
var arr = new iframeArray(1, 2, 3);
arr instanceof Array; // false(因為是不同的 Array)
對基本型別無效
'hello' instanceof String; // false
123 instanceof Number; // false
// 只有包裝物件才會是 true
new String('hello') instanceof String; // true
new Number(123) instanceof Number; // true
Array.isArray()
最可靠的陣列檢查方法:
Array.isArray([1, 2, 3]); // true
Array.isArray('hello'); // false
Array.isArray({ length: 3 }); // false
// 即使跨 frame 也能正確判斷
Array.isArray(iframeArray); // true
Object.prototype.toString.call()
最通用的型別檢查方法,可以準確區分各種內建物件:
function getType(value) {
return Object.prototype.toString.call(value);
}
getType(123); // '[object Number]'
getType('hello'); // '[object String]'
getType(true); // '[object Boolean]'
getType(undefined); // '[object Undefined]'
getType(null); // '[object Null]'
getType([]); // '[object Array]'
getType({}); // '[object Object]'
getType(function(){}); // '[object Function]'
getType(new Date()); // '[object Date]'
getType(/regex/); // '[object RegExp]'
getType(new Map()); // '[object Map]'
getType(new Set()); // '[object Set]'
可以包裝成更實用的函式:
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
typeOf(123); // 'number'
typeOf([]); // 'array'
typeOf(null); // 'null'
typeOf(new Date()); // 'date'
constructor 屬性
每個物件都有 constructor 屬性,指向建立它的建構函式:
var arr = [];
var obj = {};
var str = 'hello';
arr.constructor === Array; // true
obj.constructor === Object; // true
str.constructor === String; // true
constructor 屬性可以被修改,所以不是最可靠的檢查方式。
實用的型別檢查函式
var is = {
// 基本型別
string: function(value) {
return typeof value === 'string';
},
number: function(value) {
return typeof value === 'number' && !isNaN(value);
},
boolean: function(value) {
return typeof value === 'boolean';
},
undefined: function(value) {
return typeof value === 'undefined';
},
null: function(value) {
return value === null;
},
// 物件型別
array: function(value) {
return Array.isArray(value);
},
object: function(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
},
function: function(value) {
return typeof value === 'function';
},
date: function(value) {
return value instanceof Date && !isNaN(value);
},
regexp: function(value) {
return value instanceof RegExp;
},
// 特殊檢查
empty: function(value) {
if (value === null || value === undefined) return true;
if (Array.isArray(value) || typeof value === 'string') return value.length === 0;
if (typeof value === 'object') return Object.keys(value).length === 0;
return false;
},
numeric: function(value) {
return !isNaN(parseFloat(value)) && isFinite(value);
}
};
// 使用範例
is.string('hello'); // true
is.array([1, 2, 3]); // true
is.empty({}); // true
is.numeric('123'); // true
比較總結
| 方法 | 優點 | 缺點 |
|---|---|---|
typeof | 簡單、快速 | 無法區分物件類型,null 回傳 'object' |
instanceof | 可檢查原型鏈 | 跨 frame 失效,基本型別無效 |
Array.isArray() | 準確檢查陣列 | 只能檢查陣列 |
Object.prototype.toString.call() | 最準確、通用 | 語法較冗長 |
constructor | 可以檢查自訂類型 | 可被修改,不可靠 |
選擇建議
- 檢查基本型別(string、number、boolean):使用
typeof - 檢查陣列:使用
Array.isArray() - 檢查自訂類別的實例:使用
instanceof - 需要精確區分內建物件類型:使用
Object.prototype.toString.call()