JavaScript中的数据类型判断:typeof、instanceof、Object.prototype.toString()、Object.is的区别与手写实现

4/25/2021 Javascript

在 JavaScript 中,我们有多种方法来判断数据类型,每种方法都有其特定的用途和限制。本文将介绍并比较了解 typeof、instanceof、Object.prototype.toString()、Object.is 四种常用的数据类型判断方法,并为您提供了手写 instanceof 和 Object.is 的实现代码。

# typeof 操作符

typeof 操作符用于判断除了 null 以外的基础数据类型,但其在判断 null 时会有一些历史遗留问题。以下是 typeof 的一些示例:

typeof 1; // 'number'
typeof '1'; // 'string'
typeof undefined; // 'undefined'
typeof true; // 'boolean'
typeof Symbol(); // 'symbol'

// 特别注意
typeof null; // 'object'

# instanceof 操作符

instanceof 操作符用于判断引用类型的数据,可以检测某个对象是否是特定构造函数的实例。但对于基础类型,需要将其封装成对象后才能使用 instanceof 进行判断。以下是 instanceof 的示例:

const Person = function () {};
const p1 = new Person();
p1 instanceof Person; // true

var str1 = 'hello world';
str1 instanceof String; // false

var str2 = new String('hello world');
str2 instanceof String; // true

# 手写 instanceof

以下是手写 instanceof 的实现代码:

function myInstanceOf(left, right) {
  if (typeof left !== 'object' || left === null) return false;
  let proto = Object.getPrototypeOf(left);
  while (true) {
    if (proto === null) return false;
    if (proto === right.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
}

# Object.prototype.toString()

Object.prototype.toString() 方法是一种通用且可靠的方式,用于获取变量的内部 [[Class]] 属性,从而实现数据类型的判断。以下是使用 Object.prototype.toString() 进行数据类型判断的示例:

Object.prototype.toString.call(1); // "[object Number]"
Object.prototype.toString.call('1'); // "[object String]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(Symbol()); // "[object Symbol]"

Object.prototype.toString.call(null); // "[object Null]"

# Object.is 方法

Object.is 是 ES6 中新增的方法,用于比较两个值是否相等,修复了 === 在某些特殊情况下的不准确问题。以下是 Object.is 的示例:

0 === -0; // true
NaN === NaN; // false

Object.is(0, -0); // false
Object.is(NaN, NaN); // true

# 手写 Object.is

function is(x, y) {
  // +0和-0不是相等。
  if (x === y) {
    //运行到1/x === 1/y的时候x和y都为0,但是1/+0 = +Infinity, 1/-0 = -Infinity, 是不一样的
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    //NaN===NaN是false,这是不对的,我们在这里做一个拦截,x !== x,那么一定是 NaN, y 同理
    //两个都是NaN的时候返回true
    return x !== x && y !== y;
  }
}

# 总结

不同的数据类型判断方法在不同的情境下有其优劣,合理使用可以帮助我们更准确地处理数据类型判断问题。了解这些方法的原理和适用场景,可以在编写 JavaScript 代码时更加灵活和准确。