判断数据类型的方法及原理
1.typeof
原理: 不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位存储其类型信息。
000: 对象 、010: 浮点数 、100:字符串 、110: 布尔 、1: 整数
例:console.log(typeof 100); // number
注:typeof null 为"object",因为null的二进制表示全为0.
typeof 只能判断基础数据类型(null 除外),当判断其它数据类型时,它总是返回 object 或者 function
2.instanceof
原理: 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
(A instanceof B,判断构造函数B的prototype是否在对象A的原型链上)
例:
[] instanceof Object; // true
解析:[].__proto__.__proto__ === Object.prototype
{} instanceof Object; // true
解析:{}.__proto__ === Object.prototype
判断引用数据类型可能不准确,且无法判断基本数据类型,因为基本数据类型没有原型链,除非是用构造函数创建的数据。
let x = 123
console.log(x instanceof Number); //false
let a = new Number(123)
console.log(a instanceof Number) //true
3.constructor
原理: 查找数据的构造函数constructor属性。
可判断所有数据类型(除了undefined和null)。
console.log((undefined).constructor == undefined);//Cannot read properties of undefined (reading 'constructor')
console.log((null).constructor == Null);//Cannot read properties of undefined (reading 'constructor')
console.log((123).constructor == Number);//true
console.log('1'.constructor == String);//true
console.log(true.constructor == Boolean);//true
console.log([].constructor == Array);//true
console.log(function () { }.constructor == Function);//true
console.log({}.constructor == Object);//true
注:当修改其构造函数,constructor属性不会修改,所以用来判断数据类型可能不准确。
function Fun () { }
Fun.prototype = new String()
let fn = new Fun()
console.log(fn.constructor == String); //true
Fun.prototype = new Number()
console.log(fn.constructor == String); //true
4.Object.prototype.toString.call()
等同于jQuery中的$.type().
原理: 获取 this 对象的 [[Class]] 属性的值,[[Class]] 是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性,在es6中,[[Class]] 被废弃,而用 [[NativeBrand]]代替,用来识别某个原生对象是否为符合本规范的某一种特定类型的对象。规定使用Object.prototype.toString
方法,返回格式为 [object XXXX]
。
console.log(Object.prototype.toString.call([]) == '[object Array]'); //true
console.log(Object.prototype.toString.call(null) == '[object Null]'); //true
console.log(Object.prototype.toString.call(undefined) == '[object Undefined]'); //true
为什么要用call?
Object.prototype.toString原始作用就是获取对象类型
console.log(Object.prototype.toString()); //[object Object]
但是当基本数据类型使用toString时,是转化为字符串,因为js将基本数据类型原型上的toString方法重写了。
let val = [1, 2, 3]
console.log(val.toString()); //1,2,3
console.log(Array.prototype.toString.call(val)); //1,2,3
delete Array.prototype.toString
console.log(val.toString()) //[object Array]
val.toString()
等同于Array.prototype.toString.call(val)
,即调用构造函数中的原型方法。
当我们删除数据原型上的toString方法,再次调用toString方法时,js找不到Array原型上的方法,只能沿着原型链向上查找,找到并继承Object原型上的toString方法,执行后返回数据类型[object Array]。
如果想直接使用顶层对象的原型方法,就要用call将val的上下文指向Object,val可以执行Object原型上的toString(),可判断val的数据类型。
5.isArray (es5新增,仅判断数组)
原理:
(1).先判断vlaue
是否为对象类型,不是则返回false
(2).判断Object.prototype.toString.call(value) == '[object Array]'
Array.isArray([]); //true
Array.isArray([1]); //true
Array.isArray(new Array()); //true
Array.isArray(new Array("a", "b")); //true
Array.isArray(new Array(2)); //true
// Array.prototype 也是一个数组
Array.isArray(Array.prototype); //true