javascript类型判断

73 阅读2分钟

一、typeof

typeof只能准确判断出非null的基础数据类型及function,其他则都返回object

console.log(typeof 1);      //number
console.log(typeof "1");    //string
console.log(typeof undefined);    //undefined
console.log(typeof false);  //boolean
const a = Symbol("a");
console.log(typeof a);      //symbol
const num = BigInt(10);
console.log(typeof num);    //bigint
console.log(typeof function () { });    //function
console.log(typeof null);   //object
console.log(typeof []);     //object
console.log(typeof {});   //object

二、instanceof

instanceof通过检测给定的构造函数的prototype属性是否出现在某个实例的原型对象上来判断,底层通过Symbol.hasInstance实现,不能用以判断基本数据类型,因为它们不是对象

const arr = [1, 2, 3];
console.log(arr instanceof Array);  //true
console.log(arr instanceof RegExp); //false
const fun = function () { };
console.log(fun instanceof Function);   //true
console.log(fun instanceof Date);   //false
//Symbol.hasInstance方式:
console.log(Array[Symbol.hasInstance](arr));
console.log(Function[Symbol.hasInstance](fun));

//可通过以下方式自定义实现对基本数据类型的判断:
class myInstanceOf{
    static [Symbol.hasInstance](obj) { 
        return typeof obj === 'string';
    }
}
console.log('aye' instanceof myInstanceOf);  //true
console.log(1 instanceof myInstanceOf);  //false

三、constructor

当一个函数被定义时,js引擎会为其添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向函数的引用:

function Fun() { };
console.log(Fun.prototype);
1695896655499.jpg

当执行const f = new Fun()时,Fun为构造函数,f为实例对象,此时 Fun 原型上的 constructor 传递到了 f 上,因此 f.constructor === Fun

const f = new Fun();
console.log(f.constructor === Fun);   //true

可以看出,Fun 利用原型对象上的 constructor 引用了自身,当 Fun 作为构造函数来创建对象时,原型上的 constructor 就被传递到了新创建的对象上, 从原型链角度讲,构造函数 Fun 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。

同样,js内置对象在内部构建时也是这样做的:

console.log(''.constructor === String);     //true
console.log(Number(1).constructor === Number);     //true
console.log(true.constructor === Boolean);     //true
console.log([].constructor === Array);     //true
console.log(new Function().constructor === Function);     //true
console.log(new Date().constructor === Date);     //true

注意:

  • null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
  • 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object,因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

四、toString

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。,对于 Object 对象,直接调用 toString()  就能返回 "[object Object]" 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

console.log({}.toString());   //[object Object]
console.log(Object.prototype.toString.call(1));   //[object Number]
//配合slice截取结果:
console.log(Object.prototype.toString.call(1).slice(8, -1));   //Number
console.log(Object.prototype.toString.call('aye').slice(8, -1));   //String
console.log(Object.prototype.toString.call(null).slice(8, -1));   //Null
console.log(Object.prototype.toString.call(undefined).slice(8, -1));   //Undefined
console.log(Object.prototype.toString.call(true).slice(8, -1));   //Boolean
console.log(Object.prototype.toString.call([]).slice(8, -1));   //Array
console.log(Object.prototype.toString.call(/^$/).slice(8, -1));   //RegExp
console.log(Object.prototype.toString.call(new Function()).slice(8, -1));   //Function
console.log(Object.prototype.toString.call(new Date()).slice(8, -1));   //Date