您现在的位置是:网站首页 > 类型检测(typeof, instanceof)文章详情

类型检测(typeof, instanceof)

JavaScript作为动态类型语言,变量类型在运行时才能确定。类型检测是开发中常见的需求,主要使用typeof和instanceof操作符。

typeof操作符

typeof返回一个字符串,表示未经计算的操作数的类型。基本用法:

javascript 复制代码
console.log(typeof 42); // "number"
console.log(typeof 'blubber'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undeclaredVariable); // "undefined"
console.log(typeof {a: 1}); // "object"
console.log(typeof [1, 2, 4]); // "object"
console.log(typeof new Date()); // "object"
console.log(typeof function() {}); // "function"
console.log(typeof null); // "object" (历史遗留问题)

typeof的特殊情况:

  • 对null返回"object"是JavaScript早期实现的bug,一直保留至今
  • 函数返回"function",尽管函数本质也是对象
  • 数组返回"object",无法区分数组和普通对象

instanceof操作符

instanceof用于检测构造函数的prototype属性是否出现在对象的原型链中。基本语法:

javascript 复制代码
object instanceof constructor

示例:

javascript 复制代码
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car); // true
console.log(auto instanceof Object); // true

const simpleStr = "This is a simple string";
console.log(simpleStr instanceof String); // false (字面量不是对象)

const strObj = new String("String created with constructor");
console.log(strObj instanceof String); // true

instanceof的工作原理:

  1. 获取对象的原型:Object.getPrototypeOf(obj)
  2. 获取构造函数的prototype属性
  3. 比较两者是否相等,如果不相等则继续沿着原型链向上查找
  4. 如果找到则返回true,否则返回false

类型检测的实际应用

区分数组和对象

javascript 复制代码
function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
  // 或者使用 Array.isArray(obj)
}

console.log(isArray([])); // true
console.log(isArray({})); // false

检测NaN

javascript 复制代码
function isNaN(value) {
  // NaN是JavaScript中唯一不等于自身的值
  return value !== value;
}

console.log(isNaN(NaN)); // true
console.log(isNaN(42)); // false

安全类型检测函数

javascript 复制代码
function getType(obj) {
  if (obj === null) return 'null';
  if (obj === undefined) return 'undefined';
  
  const type = typeof obj;
  if (type !== 'object') return type;
  
  // 获取对象的[[Class]]内部属性
  const toString = Object.prototype.toString;
  const typeString = toString.call(obj);
  
  // 匹配类似[object Type]的字符串
  const match = typeString.match(/\[object (\w+)\]/);
  if (!match) return 'object';
  
  const classType = match[1].toLowerCase();
  
  // 特殊处理一些类型
  if (classType === 'number' && isNaN(obj)) return 'nan';
  if (classType === 'boolean' || classType === 'string') return classType;
  
  return classType;
}

console.log(getType([])); // "array"
console.log(getType(new Date())); // "date"
console.log(getType(/test/)); // "regexp"
console.log(getType(NaN)); // "nan"

原型链与instanceof

理解instanceof需要深入理解JavaScript的原型链机制:

javascript 复制代码
function Parent() {}
function Child() {}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

const child = new Child();

console.log(child instanceof Child); // true
console.log(child instanceof Parent); // true
console.log(child instanceof Object); // true

// 修改原型链会影响instanceof的结果
Child.prototype = {};
console.log(child instanceof Child); // false

Symbol.hasInstance

ES6引入了Symbol.hasInstance,允许自定义instanceof的行为:

javascript 复制代码
class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false

类型检测的边界情况

跨窗口/iframe问题

在不同iframe中创建的数组,instanceof Array会返回false:

html 复制代码
<iframe id="iframe"></iframe>
<script>
  const iframe = document.getElementById('iframe');
  const iframeArray = iframe.contentWindow.Array;
  const arr = new iframeArray(1, 2, 3);
  
  console.log(arr instanceof Array); // false
  console.log(Array.isArray(arr)); // true
</script>

原始值包装对象

javascript 复制代码
const str = "hello";
console.log(str instanceof String); // false

const strObj = new String("hello");
console.log(strObj instanceof String); // true

现代JavaScript的类型检测

ES6+引入了更多类型检测方法:

javascript 复制代码
// 检查数组
console.log(Array.isArray([])); // true

// 检查NaN
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("NaN")); // false

// 检查有限数字
console.log(Number.isFinite(Infinity)); // false

// 检查整数
console.log(Number.isInteger(3)); // true
console.log(Number.isInteger(3.1)); // false

// 安全整数检查
console.log(Number.isSafeInteger(Math.pow(2, 53))); // false

类型检测的性能考虑

不同类型检测方法的性能差异:

javascript 复制代码
const obj = {};
const arr = [];
const iterations = 1000000;

console.time('typeof');
for (let i = 0; i < iterations; i++) {
  typeof obj;
}
console.timeEnd('typeof');

console.time('instanceof');
for (let i = 0; i < iterations; i++) {
  arr instanceof Array;
}
console.timeEnd('instanceof');

console.time('Array.isArray');
for (let i = 0; i < iterations; i++) {
  Array.isArray(arr);
}
console.timeEnd('Array.isArray');

console.time('Object.prototype.toString');
for (let i = 0; i < iterations; i++) {
  Object.prototype.toString.call(arr) === '[object Array]';
}
console.timeEnd('Object.prototype.toString');

类型检测的最佳实践

  1. 基本类型检测优先使用typeof
  2. 数组检测使用Array.isArray()
  3. 自定义对象类型检测使用instanceof
  4. 需要精确类型信息时使用Object.prototype.toString.call()
  5. 注意null和undefined的特殊处理
  6. 跨环境类型检测要考虑iframe和不同全局上下文的情况

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdc.top

沙漏人生

站点信息

  • 建站时间:2025/06/17
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步