[JS] 数据类型与特殊值的判断方法

  • [JS] 数据类型与特殊值的判断方法已关闭评论
  • 43 次浏览
  • A+
所属分类:Web前端
摘要

由于JS是弱类型语言,判断一个变量的数据类型是一个很常见的需求。下面介绍一些常用的判断方法:

由于JS是弱类型语言,判断一个变量的数据类型是一个很常见的需求。

下面介绍一些常用的判断方法:

typeof操作符

typeof可以用来判断除了``null的基本数据类型和function,其它引用数据类型都会返回object`。

console.log(typeof "Hello"); // "string" console.log(typeof 42); // "number" console.log(typeof true); // "boolean" console.log(typeof undefined); // "undefined" console.log(typeof function(){}); // "function" 
console.log(typeof null); // "object" (这是一个历史遗留的bug) console.log(typeof []); // "object" 

为什么typeof null会返回object ?

在JS的最初版本中,使用32位二进制表示栈中的变量,二进制的前三位为类型标识tag,当前三位都是0时,表示object类型。但是null被设计为32位二进制都是0,因此会被错误地识别为object类型。

由于这个错误影响范围很大,后期并没有被修复。

👉harmony:typeof_null [ES Wiki] (archive.org)

instanceof操作符

语法:变量 instanceof 函数

返回值:布尔值,变量是否是指定的构造函数的实例,即变量的原型链上是否存在指定的构造函数

特点:只用来判断引用数据类型。

console.log([] instanceof Array); // true console.log({} instanceof Object); // true console.log(function(){} instanceof Function); // true console.log(new Date() instanceof Date); // true 

对于基础数据类型:

1 instanceof Number ==> false  let a = new Number(1); a instanceof Number ==> true 

注意instanceof在跨iframe或者不同的JavaScript执行环境时可能会失效,因为每个执行环境都有独立的构造函数。

Object.prototype.toString.call

这是最通用和可靠的方法。通过Object.prototype.toString.call方法,可以精确地判断变量的类型,不受执行环境的影响。

console.log(Object.prototype.toString.call("Hello")); // "[object String]" console.log(Object.prototype.toString.call(42)); // "[object Number]" console.log(Object.prototype.toString.call(true)); // "[object Boolean]" console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]" console.log(Object.prototype.toString.call(null)); // "[object Null]" console.log(Object.prototype.toString.call([])); // "[object Array]" console.log(Object.prototype.toString.call({})); // "[object Object]" console.log(Object.prototype.toString.call(function(){})); // "[object Function]" console.log(Object.prototype.toString.call(new Date())); // "[object Date]" 

isArray

Array.isArray在ES5就存在了,与上述的Object.prototype.toString.call方法相比:

  • Array.isArray的兼容性没有后者好,但是考虑到IE目前已经无了,基本可以放心使用;
  • Array.isArray作为原生的方法,底层实现会被引擎优化,通常比起后者的字符串比较操作性能会更好。

判断箭头函数

箭头函数的特点:

  1. toString方法返回函数体会包含=>;(这个特点作为判断标准不严谨,因为普通函数的函数体可能包含带有=>字符的语句)
  2. 箭头函数没有prototype属性,而普通函数有;
  3. 箭头函数不能被当作构造函数,因此使用new关键字实例化会抛出异常。

综合判断方法:

function isArrowFunction(func) {     if (typeof func !== 'function') {         return false;     }     try {         new func();         return false;     } catch (e) {         return !func.hasOwnProperty('prototype') && func.toString().includes('=>');     } } 

判断async函数

async函数的特点:

  1. toString方法返回的字符串带有async(开头位置);
  2. Object.prototype.toString.call会返回[object AsyncFunction]
  3. AsyncFunction构造函数的实例。(由于在大多数环境中,AsyncFunction无法直接访问,可以通过构建一个新的async函数来获得这个构造函数)。

综合判断方法:

function isAsyncFunction(func) {     if (typeof func !== 'function') {         return false;     }     const AsyncFunction = (async function() {}).constructor;     return func instanceof AsyncFunction ||             Object.prototype.toString.call(func) === '[object AsyncFunction]' ||             func.toString().trim().startsWith('async'); } 

判断class

常见方法:

  1. 使用 typeofFunction.prototype.toString:通过 typeof 检查是否是函数,然后通过 toString 检查字符串表示形式中是否包含 class 关键字;
  2. 检查原型链:类的原型链上通常会有 constructor 属性,并且这个 constructor 属性指向类自身;
  3. 使用new检查:类不能在没有 new 关键字的情况下调用,而函数可以。

综合方法:

function isClass(func) {     if (typeof func !== 'function') {         return false;     }     try {         func();         return false;     } catch (e) {         if (e.message.includes('Class constructor') || e.message.includes('class constructors')) {             return true;         }         return /^classs/.test(Function.prototype.toString.call(func));     } } 

示例文件

// is.js  /**  * 判断是否为字符串  * @param value - 需要判断的值  * @returns boolean  */ function isString(value) {     return Object.prototype.toString.call(value) === '[object String]'; }  /**  * 判断是否为数字  * @param value - 需要判断的值  * @returns boolean  */ function isNumber(value) {     return Object.prototype.toString.call(value) === '[object Number]'; }  /**  * 判断是否为布尔值  * @param value - 需要判断的值  * @returns boolean  */ function isBoolean(value) {     return Object.prototype.toString.call(value) === '[object Boolean]'; }  /**  * 判断是否为 undefined  * @param value - 需要判断的值  * @returns boolean  */ function isUndefined(value) {     return Object.prototype.toString.call(value) === '[object Undefined]'; }  /**  * 判断是否为 null  * @param value - 需要判断的值  * @returns boolean  */ function isNull(value) {     return Object.prototype.toString.call(value) === '[object Null]'; }  /**  * 判断是否为数组  * @param value - 需要判断的值  * @returns boolean  */ function isArray(value) {     return Array.isArray(value);     // return Object.prototype.toString.call(value) === '[object Array]'; }  /**  * 判断是否为对象  * @param value - 需要判断的值  * @returns boolean  */ function isObject(value) {     return Object.prototype.toString.call(value) === '[object Object]'; }  /**  * 判断是否为函数  * @param value - 需要判断的值  * @returns boolean  */ function isFunction(value) {     return Object.prototype.toString.call(value) === '[object Function]'; }  /**  * 判断是否为日期  * @param value - 需要判断的值  * @returns boolean  */ function isDate(value) {     return Object.prototype.toString.call(value) === '[object Date]'; }  /**  * 判断是否为正则表达式  * @param value - 需要判断的值  * @returns boolean  */ function isRegExp(value) {     return Object.prototype.toString.call(value) === '[object RegExp]'; }  /**  * 判断是否为错误对象  * @param value - 需要判断的值  * @returns boolean  */ function isError(value) {     return Object.prototype.toString.call(value) === '[object Error]'; }  /**  * 判断是否为 Symbol  * @param value - 需要判断的值  * @returns boolean  */ function isSymbol(value) {     return Object.prototype.toString.call(value) === '[object Symbol]'; }  /**  * 判断是否为 Promise  * @param value - 需要判断的值  * @returns boolean  */ function isPromise(value) {     return Object.prototype.toString.call(value) === '[object Promise]'; }  /**  * 判断是否为 Set  * @param value - 需要判断的值  * @returns boolean  */ function isSet(value) {     return Object.prototype.toString.call(value) === '[object Set]'; }  /**  * 判断是否为 Map  * @param value - 需要判断的值  * @returns boolean  */ function isMap(value) {     return Object.prototype.toString.call(value) === '[object Map]'; }  /**  * 判断是否为 箭头函数  * @param value - 需要判断的值  * @returns boolean  */ function isArrowFunction(func) {     if (typeof func !== 'function') {         return false;     }     try {         new func();         return false;     } catch (e) {         return !func.hasOwnProperty('prototype') && func.toString().includes('=>');     } }  /**  * 判断是否为 async函数  * @param value - 需要判断的值  * @returns boolean  */ function isAsyncFunction(func) {     if (typeof func !== 'function') {         return false;     }     const AsyncFunction = (async function() {}).constructor;     return func instanceof AsyncFunction ||             Object.prototype.toString.call(func) === '[object AsyncFunction]' ||             func.toString().trim().startsWith('async'); }  /**  * 判断是否为 class  * @param value - 需要判断的值  * @returns boolean  */ function isClass(func) {     if (typeof func !== 'function') {         return false;     }     try {         func();         return false;     } catch (e) {         if (e.message.includes('Class constructor') || e.message.includes('class constructors')) {             return true;         }         return /^classs/.test(Function.prototype.toString.call(func));     } }  /**  * 判断是否为 空对象  * @param value - 需要判断的值  * @returns boolean  */ function isEmptyObject(value) {     return isObject(value) && Object.keys(value).length === 0; }  // 导出函数 module.exports = {     // type     isString,     isNumber,     isBoolean,     isUndefined,     isNull,     isArray,     isObject,     isFunction,     isDate,     isRegExp,     isError,     isSymbol,     isPromise,     isSet,     isMap,     isArrowFunction,     isAsyncFunction,     isClass,     // value     isEmptyObject, };  

值比较

除了类型比较,JS里有一些值也是经常需要判断的。

NaN、Infinitity、Integer、safeInteger

这些和数值相关的判断都在Number的静态方法里了。

Number.isNaN(value); // 是否NaN Number.isFinite(value); // 是否有限数值  function isInfinitiy(value){ // 是否是无穷大     return !Number.isFinite(value); 	// 另一种写法     return value === Infinity || value === -Infinity; }  Number.isInteger(value); // 判断整数 Number.isSafeInteger(value); // 判断安全整数  

判断空对象

空对象指的是不包含任何可枚举属性的对象。

function isEmptyObject(value) {     return isObject(value) && Object.keys(value).length === 0; }  function isObject(value) {     return Object.prototype.toString.call(value) === '[object Object]'; }