【JavaScript】🚀 数据类型大揭秘:typeof/instanceof/toString.call 终极指南

415 阅读2分钟

前言

前面我们认识了 JavaScript 中的各种数据类型,今天就来聊聊如何判断这些类型吧!🧐

1. 🔍 typeof 操作符

1.1 简单类型判断小能手

typeof 是 JavaScript 原生的操作符,用来快速判断原始数据类型(除 null 外)。它直接读取 JS 引擎内部的类型标记。

console.log(typeof(100));        // "number"
console.log(typeof('100'));      // "string"
console.log(typeof(true));       // "boolean"
console.log(typeof(undefined));  // "undefined"
console.log(typeof(null));       // "object" 😅 (特殊!)
console.log(typeof({}));         // "object"
console.log(typeof(Symbol()));   // "symbol"
console.log(typeof(BigInt(100)));// "bigint"

1.2 为什么 typeof null === 'object'?

这是 JavaScript 早期设计的一个小“意外” 🐞:null 的内部表示是全零值,碰巧和对象的类型标记相同,所以 typeof 就把它误判为 object 啦!

2. 🔗 instanceof 操作符

2.1 检查“家族关系”

instanceof 用来检查一个对象是否属于某个构造函数或类(通过原型链查找)。

let date = new Date();
console.log(date instanceof Date); // true ✅

let set = new Set();
console.log(set instanceof Set);   // true ✅

2.2 手动实现原理

它的核心是沿着原型链向上查找:

function myInstanceof(L, R) {
  L = L.__proto__;
  while (L) { 
    if (L === R.prototype) return true;
    L = L.__proto__;
  }
  return false;
}

2.3 使用注意 ⚠️

  • 原始值(如 10, "hello")直接判断会返回 false(除非用 new 创建包装对象)。
  • nullundefined 无法使用(会报错)。
  • 没有原型的对象(如 Object.create(null))也无法判断。

3. 🎭 Object.prototype.toString.call()

3.1 类型检测“终极武器” 💪

这个方法能精准返回任何值的内部类型标签(格式为 [object Type]):

console.log(Object.prototype.toString.call(10));          // [object Number]
console.log(Object.prototype.toString.call("hi"));        // [object String]
console.log(Object.prototype.toString.call(null));        // [object Null] ✅
console.log(Object.prototype.toString.call(undefined));   // [object Undefined]
console.log(Object.prototype.toString.call(Symbol()));    // [object Symbol]
console.log(Object.prototype.toString.call([]));          // [object Array]
console.log(Object.prototype.toString.call(new Set()));   // [object Set]
console.log(Object.prototype.toString.call(function(){}));// [object Function]

3.2 为什么必须用 .call()?🤔

因为很多对象(如数组、函数)自己改写了 toString 方法:

let arr = [1, 2, 3];
console.log(arr.toString()); // "1,2,3" (数组自己的方法,不是类型信息!)

Object.prototype.toString.call(arr) 确保了:

  1. 调用最原始的 toString 方法。
  2. this 正确指向我们要检测的值 (arr),从而获取其真实的内部类型标签。

4. ✅ Array.isArray() - 数组专属检测

专为数组设计的检测方法,简单又准确!优先推荐用它来判断数组:

console.log(Array.isArray([]));              // true ✅
console.log(Array.isArray([1, 2, 3]));       // true ✅
console.log(Array.isArray(new Array(5)));    // true ✅

// 完美避开“像数组但不是数组”的对象
console.log(Array.isArray({ length: 3 }));   // false ❌
console.log(Array.isArray("hello"));         // false ❌

function test() {
  console.log(Array.isArray(arguments));    // false ❌ (arguments是类数组)
}
test();

✨ 总结一下

  • typeof: 快速判断原始类型 (小心 null 返回 "object")。
  • instanceof: 检查对象与构造函数的关系 (原型链查找)。
  • Object.prototype.toString.call(): 最通用的类型检测方法 (返回 [object Type])。
  • Array.isArray(): 判断数组的首选方法 👍。