沃梦达 / IT编程 / 前端开发 / 正文

超越Jquery_01_isPlainObject分析与重构

isPlainObject函数用于判断传入的对象是否为纯粹的JavaScript对象。具体实现如下:

超越Jquery_01_isPlainObject分析与重构

1. isPlainObject函数分析

isPlainObject函数用于判断传入的对象是否为纯粹的JavaScript对象。具体实现如下:

function isPlainObject(obj) {
  var proto, Ctor;

  // 剔除null和非对象类型
  if (!obj || {}.toString.call(obj) !== "[object Object]") {
    return false;
  }

  proto = Object.getPrototypeOf(obj);

  // 没有原型的对象为纯粹的JavaScript对象
  if (!proto) {
    return true;
  }

  // 构造函数的原型为Object的实例
  Ctor = {}.hasOwnProperty.call(proto, "constructor") && proto.constructor;
  return typeof Ctor === "function" && {}.toString.call(Ctor) === {}.toString.call(Object);
}
  • 首先判断传参是否为null或者非对象类型,如果是则返回false;
  • 然后获取对象的原型对象。
  • 没有原型对象的是普通对象(遵循ECMAScript规范),将其视为纯粹对象;
  • 通过对象原型判断对象是否通过自定义构造函数生成,如果是则从构造函数原型上查询是否存在Object构造函数,此时这个对象就被视为纯粹JS对象返回true。

2. isPlainObject函数存在的问题

虽然isPlainObject函数能够比较准确地判断传入的对象是否为纯粹JavaScript对象,但是它并没有完美的解决问题:

  1. 不支持对空对象进行判断
  2. 对于DOM节点和window对象也会认为其是普通对象
  3. 还有通过自定义函数生成的对象,如果该函数的原型链上存在Object构造函数,也会被识别为纯粹JavaScript对象,但并非如此。

3. isPlainObject函数重构

下面的代码能够对isPlainObject函数进行完美的重构:

function isPlainObject(obj) {
    // 判断是否为对象类型
    if (!obj || typeof obj !== 'object' || obj.nodeType || obj.window === obj) {
        return false;
    }

    // 是否拥有Object原型链上的isPrototypeOf属性
    if (obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
    }

    return true;
}
  • 首先,判断是否为非null的对象类型或者非window的全局对象;
  • 如果是DOM节点或全局window对象,则返回false;
  • 如果是自定义构造函数生成的对象,则无法通过Object.prototype去验证其是否具有isPrototypeOf属性,也返回false;
  • 如果存在isPrototypeOf属性,则一定为纯粹对象。

4. 示例说明

例如,在以下的情况下,isPlainObject函数就会存在不准确的情况:

// 定义一个自定义构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 调用自定义构造函数创建对象
var person1 = new Person('张三', 18);
var isPureObject1 = $.isPlainObject(person1); // 这里将被识别为纯粹对象,因为Person的原型链上存在Object构造函数

// 如下的情况则不会被题识别为纯粹对象,因为obj定义即为空对象
var obj = {};
var isPureObject2 = $.isPlainObject(obj); // 这里也会被误认为不是纯粹对象。

最终,通过isPlainObject函数重构,能够避免以上两种情况的误判。

本文标题为:超越Jquery_01_isPlainObject分析与重构