读过小红书的人都知道,JavaScript判断数据类型的方法大致有以下几种:
- typeof
- instanceof
- constructor 下面就总结一下这几种方法的优缺点 首先定义一些初始变量
var num = 123;
var str = 'abcdef';
var bool = true;
var arr = [1, 2, 3, 4];
var obj = {name:'wenzi', age:25};
var func = function(){ console.log('this is function'); }
var und = undefined;
var nul = null;
var date = new Date();
var reg = /^[a-zA-Z]{5,20}$/;
var error= new Error();
typeof
typeof用以获取一个变量或者表达式的类型-一般用于判断值类型
typeof num, // number
typeof str, // string
typeof bool, // boolean
typeof arr, // object
typeof obj, // object
typeof func, // function
typeof und, // undefined
typeof nul, // object
typeof date, // object
typeof reg, // object
typeof error // object
可以看出arr, json, nul, date, reg, error 全部被检测为object类型,其他的变量能够被正确检测出来。当需要变量是否是number, string, boolean, function, undefined类型时,可以使用typeof进行判断。其他引用类型以及null是判断不出类型的
instanceof
instanceof 运算符是用来判断一个对象是否在其原型链原型构造函数的属性,所以在比较对象(引用类型)时才有意义
num instanceof Number, // false
str instanceof String, // false
bool instanceof Boolean, // false
arr instanceof Array, // true--注意
arr instanceof Object, // true--注意
obj instanceof Object, // true--注意
func instanceof Function, // true
und instanceof Object, // false
nul instanceof Object, // false
date instanceof Date, // true
reg instanceof RegExp, // true
error instanceof Error // true
从结果可以看出instanceof不能判断值类型,但是引用类型可以,值得注意的是arr和obj在instanceof Object的时候的值都是true,这就导致判断是对象时不准确
constructor
constructor本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的
function Person(){}
var Tom = new Person();
// undefined和null没有constructor属性
console.log(
Tom.constructor==Person,
num.constructor==Number,
str.constructor==String,
obj.constructor==Boolean,
arr.constructor==Array,
json.constructor==Object,
func.constructor==Function,
date.constructor==Date,
reg.constructor==RegExp,
error.constructor==Error
);
// 所有结果均为true
表面上看很完美,但是有两个缺点:
undefined和null没有constructor属性
,所以判断时代码可能会报错
--这很致命,会导致代码运行不下去,所以只有在确定待判断的值不是undefined和null才能使用- 由于
constructor属性是可以变更
的,也会导致检测出的结果不正确
通用完美的判断方法
Object.prototype.toString.call(num), // '[object Number]'
Object.prototype.toString.call(str), // '[object String]'
Object.prototype.toString.call(bool), // '[object Boolean]'
Object.prototype.toString.call(arr), // '[object Array]'
Object.prototype.toString.call(obj), // '[object Object]'
Object.prototype.toString.call(func), // '[object Function]'
Object.prototype.toString.call(und), // '[object Undefined]'
Object.prototype.toString.call(nul), // '[object Null]'
Object.prototype.toString.call(date), // '[object Date]'
Object.prototype.toString.call(reg), // '[object RegExp]'
Object.prototype.toString.call(error) // '[object Error]'
ECMA里规范定义了Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于”[object Array]”的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。