超越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对象,但是它并没有完美的解决问题:
- 不支持对空对象进行判断
- 对于DOM节点和window对象也会认为其是普通对象
- 还有通过自定义函数生成的对象,如果该函数的原型链上存在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分析与重构 - Python技术站