判断数据类型的方法

68 阅读2分钟

typeof

console.log(typeof 2); // number 
console.log(typeof true); // boolean 
console.log(typeof 'str'); // string 
console.log(typeof []); // object 
console.log(typeof function(){}); // function 
console.log(typeof {}); // object 
console.log(typeof undefined); // undefined 
console.log(typeof null); // object

问题 只能检测基本数据类型

instanceof

instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型

console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false 
 
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true

可以看到,instanceof只能正确判断引用数据类型,而不能判断基本数据类型。instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

constructor

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
  • 语法 数据结构.constructor

  • 问题:null 和undefind 不能使用

  • 使用场景:一般用于引用数据类型

  • 潜在问题:这是原型对象的某一个属性,我们是可以手动更改的

constructor有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了:

Array.isArray()

Array.isArray() 用于确定传递的值是否是一个数组。

Array.isArray([1, 2, 3]);// true
Array.isArray([1,2,3,NaN]);// true
Array.isArray({foo: 123});// false
Array.isArray("foobar");// false
Array.isArray(undefined);// false
Array.isArray(NaN);// false

语法:Array.isArray(arg)

模拟实现

Array.myIsArray = (arg) => {
  return Object.prototype.toString.call(arg) === '[object Array]'
}

Object.prototype.toString.call(要检测的数据)

Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:

Object.prototype.toString.call(a)   '[object String]'
Object.prototype.toString.call(b)   '[object Boolean]'
Object.prototype.toString.call(c)   '[object String]'
Object.prototype.toString.call(d)   '[object Number]'
Object.prototype.toString.call(e)   '[object Function]'
Object.prototype.toString.call(f)   '[object Undefined]'
Object.prototype.toString.call(g)   '[object Null]'
Object.prototype.toString.call(h)   '[object RegExp]'
Object.prototype.toString.call(i)   '[object Object]'
Object.prototype.toString.call(k)   '[object Array]'
  • 返回值object 数据类型

  • 使用场景:任意类型都可准确判断,所以大部分情况下都可以使用

  • 缺点 不能识别非原生构造函数(就是不能识别自己写的构造函数)

class Point{
	constructor(x,y){
		this.x = x;
		this.y = y;
	}
	toValue(){
		return this.x+this.y;
	}
}
let p = new Point(1,2);
Object.prototype.toString.call(p); //返回"[object Object]"
p instanceof Point;                //返回true
注意:Object.prototype.toString方法还可能被覆写。

webpack源码更青睐typeof,instanceof,和Array.isArray,比如截取的这段代码,用来解析module.rules中某个规则的test、include和exclude字段,这3个字段的值可以是字符串、函数、正则表达式和数组。

Vue源码做类型检测时,也很喜欢typeof,instanceof 和Array.isArray()。只是在做严格的类型检测时,会使用到Object.prototype.toString。

日常开发中,typeof,instanceof 和Array.isArray()能够满足所需,Object.prototype.toString.call更像是锦上添花,但是,Object.prototype.toString.call有原生的限制,它拿非原生构造函数没啥办法。