[基础]封装数据类型检测方法

303 阅读3分钟

整理数据类型检测。附加几个jquery中的检测方法

复习js中数据类型检测的四种方法

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString.call

typeof

最常用的方法,虽然不准确,对付一般情况也是够用

  • 检测数据类型的 逻辑运算符
  • 返回结果都是 字符串
  • 返回结果有:
    • "string""number""boolean""undefined""symbol"
    • "object""function"

通过返回的字符串就能看出 typeof 的局限性,有几个不能:

  1. 不能检测null,typeof null === 'object'
  2. 不能区分正则、时间等对象
  3. 不能检测array

自我检测: typeof typeof [] 的值是什么。答:"string"

instanceof

检测某个实例是不是这个类

底层机制:所有出现在其原型链上的类

由于这个机制会出现两个问题。1.判断出的对象不一定是真的对象。2.原型链可以更改,类型不能完全相信。看下面两个例子

console.log([] instanceof Array) // true
console.log([] instanceof Object) // true

function Fn(){}
Fn.prototype = Array.prototype
console.log((new Fn()) instanceof Array) // true

不支持基本类型字面量判断

console.log(12 instanceof Number) // false
console.log(new Number(12) instanceof Number) // true

constructor

原理:constructor 指向构造函数

与 instanceof 很像,做一下对比。

\ 遍历整个原型链 手动更改 可靠 机制
instanceof x 查找原型链
constructor x x 属性访问

Object.prototype.toString (最可靠的方法)

原理:利用 Object.prototype.toString 上的特殊性。注意不是所有 toString 方法都行!!!

xxx.prototype.toString 方法总结

  • 除undefined、null外的基本类型:转化为字符串
    • undefined与null是不能属性查找的,不能调取toString
  • Array、RegExp、Function等内置类:转化为字符串
  • Object: 当前实例所属类的信息 [object Xxxx]

jquery数据类型检测简化版,附加几个常用检测方法

$.type

jquery 源码中有个 toType 方法,其实就是 $.type

类型判断流程

  1. 核心判断
  2. 判断 null、undefined
  3. 基础类型。调用 typeof
  4. 引用类型。调用 Object.prototype.toString
  5. 骚操作
  6. 创建一个例如 {[object Array]: "array"} 的对象。方便"[object Array]"直接调取 "array"

代码如下:

var class2type = {};
var toString = Object.prototype.toString;

// 创建一个例如 {[object Array]: "array"} 的对象
"Boolean Number String Function Array Date RegExp Object Error Symbol".split(" ").forEach(function anonymous(item) {
  class2type["[object " + item + "]"] = item.toLowerCase();
});

function toType(obj) {
  // 首先判断 null、undefined
  if (obj == null) {
    return obj + ""; // 返回 "null"、"undefined"
  }

  // 如果是引用类型:调用 toString 返回 class2type 中对应的类型
  // 如果是基本类型:返回 typeof 的结果
  return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" :
    typeof obj;
}

$.isWindow

核心:利用 window === window.window

function isWindow(obj) {
  return obj != null && obj === obj.window;
};

$.isPlainObject

检测是否是纯粹对象

  • 核心判断
    • Object.prototype.toString 直接过滤掉包括 array、function 在内的所有数据类型
    • 判断原型
      • 特殊情况:没有原型,返回true
        • 解释:由 Object.create(null) 创建的对象没有原型
      • 有原型
        • 原型上有 constructor,并且 constructor 是 Object,返回true
        • 否则,返回false
function isPlainObject(obj) {
  var proto, Ctor;
  // 过滤掉包括 array、function 在内的所有数据类型
  if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") {
    return false;
  }
  // 获取当前对象的原型
  proto = Object.getPrototypeOf(obj);
  // 特殊情况 Object.create(null)
  if (!proto) {
    return true;
  }
  // 获取 constructor
  Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
  // 判断 constructor 是 Object
  return typeof Ctor === "function" && Function.prototype.toString.call(Ctor) === Function.prototype.toString.call(Object);
};

$.isEmptyObject

是否是空对象

核心:循环遍历每一项,看是否是空

function isEmptyObject(obj) {
  var name;
  for (name in obj) {
    return false;
  }
  return true;
};

$.isArrayLike

是否为数组或者类数组

  • 核心判断
    • 判断真数组
      • toType
    • 判断类数组
      • 判断是否有 length
        • 排除 function、window
        • length 是数字
        • 如果length > 0, 类数组存在 length-1 的属性
function isArrayLike(obj) {
  // 判断是否有 length
  var length = !!obj && "length" in obj && obj.length,
    type = toType(obj);
  // 排除 function、window
  if (isFunction(obj) || isWindow(obj)) {
    return false;
  }
  // 判断真数组; length 是数字; 如果length > 0, 类数组存在 length-1 的属性
  return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj;
};