Javascript高级篇之类型判断的三种方式及其隐藏细节

511 阅读4分钟

本人已参与「新人创作礼」活动,一起开启掘金创作之路。

数据类型

在js中的数据类型有:

  • Number (数字)
  • String(字符)
  • Boolean(布尔)
  • Undefined(undefined)
  • Null(null)
  • Array(数组)
  • Object(对象)
  • Date(时间)
  • Function(函数)

常规我们判断数据类型的方法有三种

  • Object.prototype.toString.call() (最推荐,最稳妥的判断方法)
  • typeof (不推荐有坑)
  • instanceof(不推荐有大坑)

typeof类型检测 和typeof的坑

typeof使用方法简单而且一般情况下可以满足项目需求,应该是我们所最为熟知的一种判断类型的方法的了。

但在一些对判断方法有过封装的大项目来说,typeof的出场率不高。 因为使用typeof进行数据类型判断有盲区,他只能返回一些简单的数据类型,复杂的一律返回object,所以使用typeof部分类型无法得出精确的结论。

举个例子👇

const num = 1;
const str = "str";
const arr = [1, 2];
const obj = { a: 1, b: 2 };
const bool = true;
const unde = undefined;
const _null = null;
const date = new Date();
const fun = function(){};

console.log(typeof num);  //number
console.log(typeof str);  //string
console.log(typeof arr);  //object  注意,判断数组返回的是对象
console.log(typeof obj);  //object 判断对象返回的也是对象
console.log(typeof bool); // boolean
console.log(typeof unde); //undefined
console.log(typeof _null); //object 就连判断null返回的都是对象
console.log(typeof date);  //object 判断时间类型返回的也是对象
console.log(typeof fun); //function

在上面例子中,不难发现。使用typeof在判断 array类型object类型null类型date类型等类型的时候会统一返回object

所以,我们就无法使用typeof获取每个类型的精确结果。

instanceof类型检测和instanceof的坑

instanceof是检测数组的一把好手。使用typeof检测数组的时候会返回对象,所以我们可以用instanceof来检测数组

像这样

console.log(arr instanceof Array)   //true

但instanceof也有坑,而且还是最坑的那一个。instanceof是检测数据构造函数的。所以,在某些情况下,检测同一类型的数据,会得出不同的结果。

举个例子

const num1 = new Number(1);  //number类型
const num2 = 1;  //也是number类型

console.log(num1 instanceof Number);  //true
console.log(num2 instanceof Number);  //false

当一些基本数据类型使用 new Number()来构建的时候,instanceof是可以检测的。

但是当这些基本类型数据是使用语法糖来构建的时候。instanceof是检测不出来的。

因为使用语法糖所构建的变量和使用构造函数构建的变量是不一样的。语法糖构建的变量没有确切的构造函数。

上面是使用Number做的示例,String,boolean等基本类型同理。

所以instanceof用来检测数组是可以的。但其他类型就不推荐了。

Object.prototype.toString.call()。类型检测救星,这是个好东西

不比typeof和instanceof这两种有各自的优点也有各自的坑。

Object.prototype.toString.call()是检测类型最好的一种方式。他几乎是全能的。

举个例子

const num = 1;
const str = "str";
const arr = [1, 2];
const obj = { a: 1, b: 2 };
const bool = true;
const unde = undefined;
const _null = null;
const date = new Date();
const fun = function(){};

console.log(Object.prototype.toString.call(num));  //[object Number]
console.log(Object.prototype.toString.call(str)); //[object String]
console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(obj),);// [object Object]
console.log(Object.prototype.toString.call(bool)); // [object Boolean]
console.log(Object.prototype.toString.call(unde)); // [object Undefined]
console.log(Object.prototype.toString.call(_null)); // [object Null]
console.log(Object.prototype.toString.call(date)); // [object Date]
console.log(Object.prototype.toString.call(fun)); // [object Function]

使用Object.prototype.toString.call()方法几乎可以检测所有的类型。

是我们在项目中最首选的使用方式。

文章提供已经封装好了可以检测所有类型的函数。读者可以直接复制使用。

封装好的检测函数👇

/*
    判断文件  is.js
*/

const toString = Object.prototype.toString;

export const is = (val, type): boolean => toString.call(val) === `[Object ${type}]`;

//判断非undefined
export const isDef = (val): boolean => typeof val !== 'undefined';

//判断是undefined
export const isUnDef = (val): boolean => !isDef(val);

//判断是否是对象
export const isObject = (val): boolean => val !== null && toString.call(val) === `[object Object]`;

export const isEmpty = (val):boolean => {
    if (isArray(val) || isString(val)) return val.length === 0;

    if (val instanceof Map || val instanceof Set) return val.size === 0;

    if (isObject(val)) return Object.keys(val).length === 0;

    return;
}

//判断是否是时间类型
export const isDate = (val): boolean => is(val, "Date");

//判断是否是null类型
export const isNull = (val): boolean => val === null;

//判断不可访问类型
export const isNullAndUnDef = (val): boolean => isUnDef(val) && isNull(val);

//判断undefined和null其中一个
export const isNullOrUnDef = (val): boolean => isUnDef(val) || isNull(val);

//判断是否是数字类型
export const isNumber = (val): boolean => is(val, "Number");

//判断是否是Promise类型
export const isPromise = (val): boolean => {
    return (
        is(val, "promise") &&
        isObject(val) &&
        isFunction(val.then) &&
        isFunction(val.catch)
    )
}

//判断是否是字符类型
export const isString = (val): boolean => is(val, "string");

//判断是否为函数
export const isFunction = (val): boolean => typeof val === "function";

//判断是否为booean类型
export const isBoolean = (val): boolean => is(val, "boolean");

//判断是否是正则表达式
export const isRegExp = (val): boolean => is(val, "RegExp");

//判断是否是数组
export const isArray = (val): boolean => val && Array.isArray(val);

//判断是否是window对象
export const isWindow = (val): boolean => typeof window !== "undefined" && is(val, "window");

结论

  • Object.prototype.toString.call();他几乎可以检测所有的数据类型(最推荐)
  • typeof只能进行基本数据类型检测,复杂数据类型(包括null类型)都会返回object(不推荐)
  • instanceof 适合用于检测数组,但是一些使用语法糖创建的基本数据类型无法识别。(有大坑,不推荐)
欢迎技术沟通,摸鱼聊天~

备注来自掘金~

wx:XXF1096032096