1.typeOf
该方法是开发中经常用到的判断数据类型的方法。其返回的数据类型包含以下7种:number、boolean、symbol、string、object、undefined、function。而我们知道JavaScript的基本数据类型有6种分别是 string、number、boolean、symbol、undefined、null。引用类型有object, Array, Date, Regexp,Function,Error。因此可以发现,该方法对于基本类型,除了null外,其余类型的判断都可以返回想要的结果。但null有自己的类型,typeof返回结果却是object。
console.log(typeof null) // object
对于引用类型。该方法除了对function返回function类型外,其余均返回object。而引用类型中的 数组、日期、正则等也都有属于自己的具体类型,但typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 object 类型。
console.log(typeof new Function()) // function
console.log(typeof new Error()) // object
console.log(typeof new RegExp()) // object
2.constructor属性
我们知道构造函数的原型对象里面有一个 constructor 属性 ,它指回构造函数本身。利用这个属性也可以进行类型判断。当我们访问某个对象实例的constructor属性,js会沿着原型链向上查找。即会查找该实例的_proto_
属性,通过该属性找到对象原型。而对象原型的constructor属性则指向该实例的构造函数。下面举例说明
function Person (){
this.name = '小明'
}
const person = new Person()
console.log(Person.prototype)
console.log(Person)
console.log(person)
我们将原型,构造函数,对象实例分别打印出来看一下

可以发现,对象实例的_proto_
指向对象原型,原型的constructor指回构造函数。下面使用该属性判断类型。
console.log(person.constructor === Person) // true
// 更多地
const arr = [1,2]
console.log(arr.constructor === Array) // true
console.log(new Error().constructor == Error) // true
注:null 和 undefined 是无效的对象,他们没有constructor属性。
3.instanceof
该方法主要用于引用类型的判断,用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。该方法的判断原则是:沿着原型链检测,判断B是否在A的原型链上。下面用例子说明:
const arr = [1,2]
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true
Array,Objectd都在数组对象的原型链上,因此都返回true,这就反应了一个问题,就是该方法只能判断两者是否是实例与构造函数的关系,而不能判断其具体类型。
我们知道该方法的实现原理就是判断B是否在A的原型链上,因此可以基于这条原则自己实现一个instanceof方法。
const myInstanceof = (left, right) => {
// 基本数据类型都返回false
if (typeof left !== 'object'&&typeof left !== 'function'||left === null) return false;
let leftProto = left.__proto__ // 获取左边对象的原型
let rightProto = right.prototype // 获取右边构造函数的原型
// 沿着原型链向上查找
while(leftProto)
{
if(leftProto === rightProto) return true
// leftProto = leftProto.__proto__ 不推荐使用__proto__ 属性
leftProto = Object.getPrototypeOf(leftProto)
}
return false
}
const arr = [1,2]
const foo = () => {
console.log('xiaom')
}
console.log(myInstanceof(arr,Array)) // true
console.log(myInstanceof(arr,Object)) // true
console.log(myInstanceof(foo,Array)) // false
console.log(myInstanceof(foo,Function)) // true
console.log(myInstanceof(foo,Object)) // true
3.Object.prototype.toString
该方法是判断类型最准确的方法。利用Object 的原型方法(Object.prototype.toString),调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object xxx] ,其中 xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来强制调用。 这里要说明一点,虽然所有的对象的原型链最终都指向了Object。按理说也都应该可以调用toString()方法,但实际上大多数对象都实现了自己的toString()方法。根据原型链的查找规则,对象调用toString时会首先访问自己实现的该方法。因此必须使用上述方法来让其强制执行Object原型上的toString()方法。
Object.prototype.toString.call('str'),// [object String]
Object.prototype.toString.call(12),// [object Number]
Object.prototype.toString.call([1,2]),//[object Array]
Object.prototype.toString.call(false),//[object Boolean]
Object.prototype.toString.call(undefined) ,// [object Undefined]
Object.prototype.toString.call(null),// [object Null]
Object.prototype.toString.call(new Function()) ,// [object Function]
Object.prototype.toString.call(new Date()), // [object Date]
Object.prototype.toString.call(new RegExp()), // [object RegExp]
Object.prototype.toString.call(new Error()) // [object Error]
可以看到,该方法虽然能准确判断类型,但返回结果不够直观。我们可以基于该方法结合正则表达式实现一个通用的类型判断函数。
function checkType(val) {
return Object.prototype.toString
.call(val)
// 匹配object后的字符
.replace(/^\[object (\S+)\]$/, "$1");
}
console.log(checkType(1)) // Number
console.log(checkType('2')) // String
console.log(checkType({name:'123'})) // Object
console.log(checkType([1,2,3])) // Array
console.log(checkType(new RegExp())) // RegExp
console.log(checkType(()=>{console.log('123')})) // Function
网友评论