JS中typeof與instanceof關鍵詞的使用解析
在JavaScript中,typeof和instanceof是用於類型檢測的核心運算符,但適用場景和檢測邏輯截然不同:typeof主要檢測基本數據類型(也可檢測函數),返回字符串類型的結果;instanceof檢測引用類型的原型鏈,判斷對象是否為某個構造函數的實例。掌握二者的區別與適用場景,是編寫健壯類型判斷邏輯的關鍵,尤其在處理動態數據、參數校驗時不可或缺。
一、typeof的基礎用法
1. 核心語法與規則
typeof是一元運算符,語法為typeof 操作數(或typeof(操作數)),返回一個字符串,表示操作數的類型。核心規則:
- 檢測基本類型(string/number/boolean/undefined/symbol/bigint):返回對應類型名稱的字符串;
- 檢測
null:返回"object"(JS歷史設計缺陷,需特殊處理); - 檢測函數:返回
"function"; - 檢測其他引用類型(對象/數組/正則等):均返回
"object"。
2. 完整檢測示例
// 1. 基本類型檢測
console.log(typeof "hello"); // "string"
console.log(typeof 123); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol("key")); // "symbol"
console.log(typeof 123n); // "bigint"(ES2020新增)
// 2. 特殊值null
console.log(typeof null); // "object"(經典bug,需記住)
// 3. 引用類型檢測
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof /abc/); // "object"
console.log(typeof new Date()); // "object"
// 4. 函數檢測
console.log(typeof function() {}); // "function"
console.log(typeof class {}); // "function"(class本質是函數)
console.log(typeof console.log); // "function"
3. 實用技巧:修復null的檢測
結合typeof和值判斷,可精準檢測null:
function isNull(value) {
return value === null && typeof value === "object";
}
console.log(isNull(null)); // true
console.log(isNull(undefined)); // false
二、instanceof的基礎用法
1. 核心語法與規則
instanceof是二元運算符,語法為對象 instanceof 構造函數,返回布爾值:
- 核心邏輯:檢測構造函數的prototype是否存在於對象的原型鏈上;
- 僅適用於引用類型(對象/數組/函數/類實例等),檢測基本類型始終返回
false; - 支持自定義構造函數/類的實例檢測,可跨原型鏈檢測(如數組既是
Array實例,也是Object實例)。
2. 完整檢測示例
// 1. 原生引用類型檢測
const arr = [1,2,3];
const obj = { name: "張三" };
const fn = () => {};
const date = new Date();
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true(數組原型鏈指向Object.prototype)
console.log(obj instanceof Object); // true
console.log(fn instanceof Function); // true
console.log(date instanceof Date); // true
console.log(date instanceof Object); // true
// 2. 基本類型檢測(始終false)
console.log("hello" instanceof String); // false
console.log(123 instanceof Number); // false
console.log(true instanceof Boolean); // false
// 3. 包裝對象檢測(基本類型的包裝對象是引用類型)
const strObj = new String("hello");
console.log(strObj instanceof String); // true
console.log(strObj instanceof Object); // true
3. 自定義構造函數/類的實例檢測
// 自定義構造函數
function Person(name) {
this.name = name;
}
const p = new Person("李四");
console.log(p instanceof Person); // true
console.log(p instanceof Object); // true
// ES6類
class Student extends Person {
constructor(name, id) {
super(name);
this.id = id;
}
}
const s = new Student("王五", 1001);
console.log(s instanceof Student); // true
console.log(s instanceof Person); // true(繼承關係,原型鏈包含Person.prototype)
console.log(s instanceof Object); // true
三、typeof與instanceof的核心區別
| 特性 | typeof | instanceof |
|---|---|---|
| 檢測目標 | 主要檢測基本類型,可檢測函數 | 僅檢測引用類型的原型鏈 |
| 返回值 | 字符串(如"string"/"object") | 布爾值(true/false) |
| 檢測邏輯 | 基於值的底層類型標籤 | 基於原型鏈的繼承關係 |
| 對null的檢測 | 返回"object"(缺陷) | null instanceof Object → false |
| 對基本類型包裝對象 | 如new String() → "object" | 如new String() instanceof String → true |
| 跨窗口/iframe檢測 | 結果一致 | 可能失效(不同窗口的構造函數原型不同) |
四、核心應用場景
1. 參數類型校驗(typeof)
函數參數校驗時,優先用typeof檢測基本類型,確保參數符合預期:
function calculateTotal(price, count) {
// 檢測price是否為數字
if (typeof price !== "number" || isNaN(price)) {
throw new Error("價格必須是有效數字");
}
// 檢測count是否為數字,且默認值為1
if (typeof count !== "number" || isNaN(count)) {
count = 1;
}
return price * count;
}
console.log(calculateTotal(10, 5)); // 50
console.log(calculateTotal(20)); // 20
// calculateTotal("20", 5); // 拋出錯誤:價格必須是有效數字
2. 區分數組與普通對象(instanceof)
typeof無法區分數組和普通對象,需用instanceof(或Array.isArray()):
function isArray(value) {
// 推薦用Array.isArray(更可靠,跨窗口也有效)
// return Array.isArray(value);
return value instanceof Array;
}
const data = [1,2,3];
const info = { name: "張三" };
console.log(isArray(data)); // true
console.log(isArray(info)); // false
3. 判斷類實例(instanceof)
在面向對象編程中,用instanceof判斷對象是否為某個類的實例,實現多態邏輯:
class Animal {
makeSound() {}
}
class Dog extends Animal {
makeSound() {
console.log("汪汪汪");
}
}
class Cat extends Animal {
makeSound() {
console.log("喵喵喵");
}
}
// 統一處理不同動物的叫聲
function playSound(animal) {
if (animal instanceof Animal) {
animal.makeSound();
} else {
console.error("不是動物實例");
}
}
playSound(new Dog()); // 汪汪汪
playSound(new Cat()); // 喵喵喵
playSound({}); // 不是動物實例
4. 動態類型判斷(組合使用)
結合typeof和instanceof,實現全類型的精準判斷:
function getValueType(value) {
// 處理null
if (value === null) {
return "null";
}
// 處理基本類型
const basicType = typeof value;
if (["string", "number", "boolean", "undefined", "symbol", "bigint"].includes(basicType)) {
return basicType;
}
// 處理引用類型
if (value instanceof Array) {
return "array";
}
if (value instanceof Date) {
return "date";
}
if (value instanceof RegExp) {
return "regexp";
}
if (typeof value === "function") {
return "function";
}
// 其他對象
return "object";
}
console.log(getValueType(null)); // "null"
console.log(getValueType([1,2])); // "array"
console.log(getValueType(new Date())); // "date"
console.log(getValueType(() => {})); // "function"
console.log(getValueType({})); // "object"
五、使用注意事項
1. typeof檢測NaN/Infinity
NaN和Infinity的類型仍是"number",需額外判斷:
console.log(typeof NaN); // "number"
console.log(typeof Infinity); // "number"
// 檢測有效數字
function isNumber(value) {
return typeof value === "number" && !isNaN(value);
}
console.log(isNumber(123)); // true
console.log(isNumber(NaN)); // false
2. instanceof跨窗口/iframe失效
不同窗口(iframe)的構造函數原型不同,導致instanceof檢測失效,優先用更可靠的方法:
// 跨窗口檢測數組(推薦用Array.isArray)
const iframeArr = window.frames[0].Array(1,2,3);
console.log(iframeArr instanceof Array); // false(不同窗口的Array原型不同)
console.log(Array.isArray(iframeArr)); // true(可靠)
// 跨窗口檢測對象(用Object.prototype.toString)
function isPlainObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
console.log(isPlainObject(window.frames[0].{})); // true
3. 避免過度依賴instanceof
instanceof依賴原型鏈,若原型鏈被修改,檢測結果會出錯:
const arr = [1,2,3];
// 修改原型鏈
Object.setPrototypeOf(arr, Object.prototype);
console.log(arr instanceof Array); // false(原型鏈被破壞)
console.log(Array.isArray(arr)); // true(仍可靠)
4. Object.prototype.toString的補充方案
對於複雜類型檢測,Object.prototype.toString.call()是更通用的方案,返回標準的類型字符串:
function getRawType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
console.log(getRawType(null)); // "null"
console.log(getRawType([])); // "array"
console.log(getRawType(new Date())); // "date"
console.log(getRawType(/abc/)); // "regexp"
console.log(getRawType(123)); // "number"
總結
typeof核心用於檢測基本類型(string/number/boolean/undefined/symbol/bigint)和函數,返回字符串,需注意null返回"object"的缺陷;instanceof核心用於檢測引用類型的原型鏈,判斷對象是否為某個構造函數/類的實例,僅返回布爾值,跨窗口檢測可能失效;- 實用技巧:參數校驗用
typeof,引用類型細分(數組/日期等)優先用Array.isArray()或Object.prototype.toString,類實例判斷用instanceof; - 二者互補使用,可覆蓋大部分類型檢測場景,是JS類型安全的基礎工具。