超越Jquery_01_isPlainObject分析与重构


Posted in Javascript onOctober 20, 2010

isPlainObject是Jquery1.4后提供的新方法,用于判断对象是否是纯粹的对象(通过 "{}" 或者 "new Object" 创建的)。

使用isPlainObject

首先我们来了解一下什么叫'纯粹的对象',简单的理解'纯粹的对象'指的就是由Object构造出来的对象。那哪些对象是由Object构造出来的呢。首当其充的肯定是由new Object()所构造出来的对象,注意:在Object后的括号里可没加任何东西。因为Object是所有'类'的根基,因此它有一些特殊的行为,如当调用new Object(3)的时候,会构造一个Number类型的对象。new Object('')会构造一个String类型的对象。然后以{}这种形式定义的对象也属于'纯粹的对象'。'{}'的实质就是new Object(),只是表现形形式不同。好,让我们来看一段代码:

var objStr = new Object(''); 
alert(objStr.constructor);//String 
alert(isPlainObject(objStr));//false 
var objNum = new Object(3); 
alert(objNum.constructor);//Number 
alert(isPlainObject(objNum));//false 
function Person(){} 
var person = new Person(); 
alert(isPlainObject(person));//false 
var obj01 = new Object(); 
obj01.name = '笨蛋的座右铭'; 
alert(isPlainObject(obj01));//true 
alert(isPlainObject({name:'笨蛋的座右铭'}));//true

isPlainObject源码分析
以下代码为Jquery中的isPlainObject的完整版本,注释已经很详尽了,我就不多说什么了。
var toString = Object.prototype.toString, 
hasOwnProperty = Object.prototype.hasOwnProperty; 
function isPlainObject( obj ) { 
// Must be an Object. 
// Because of IE, we also have to check the presence of the constructor property. 
//Make sure that DOM nodes and window objects don't pass through, as well 
//windows objects:toString.call(window):IE [object Object] FF [object Window] chrome [window global] safari [object DOMWindow] 
//DOM nodes:toString.call(#div01):IE [object Object] FF [object Window] chrome [object global] safari [object DOMWindow] 
//结论:obj.nodeType || obj.setInterval主要是针对于IE浏览器进行判断 
//注:history,location,navigator,screen的setInterval为undefined 
if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { 
return false; 
} 
// Not own constructor property must be Object 
// 除去自定义对象和内置对象的判断,如function Person(){} var p = new Person();String,Number 
if ( obj.constructor //有constructor属性 
&& !hasOwnProperty.call(obj, "constructor") //并且constructor这个属性必须是在原型链中进行定义的 
&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")//并且原型中有isPrototypeOf方法,一般只有Object的原型中才有这个方法 
) { 
return false; 
} 
// Own properties are enumerated firstly, so to speed up, 
// if last one is own, then all properties are own. 
//针对于复杂类结构,如有继承... 
/* 
//一个简单的测试 
function Animal(name){ 
} 
function Person(name,age){ 
Animal.call(this,name); 
this.age =age; 
} 
var p = new Person('jxl',20); 
for(key in p){ 
alert(hasOwnProperty.call( p, key ))//true , false 
} 
*/ 
var key; 
for ( key in obj ) {} 
return key === undefined || hasOwnProperty.call( obj, key ); 
}

提出问题
个人感觉这个实现比较复杂,而且有BUG。
简单的BUG,history,location,navigator,screen可以顺序通过 isPlainObject的检测返回true.
来看一个我的解决方案(修改BUG,简化):
function isPlainObject(obj){ 
if(obj&&Object.prototype.toString.call(obj)==="[object Object]"&&obj.constructor===Object &&!hasOwnProperty.call(obj, "constructor")){ 
var key; 
for ( key in obj ) {} 
return key === undefined || hasOwnProperty.call( obj, key ); 
} 
return false; 
}

还有BUG,而且是一个无解的BUG:
function m(){}; 
m.prototype.constructor=Object; //必杀 
obj=new m; 
alert(isPlainObject(obj)); //true

再来一个同理的:
function m(){}; 
m.prototype = {}; 
obj=new m; 
alert(isPlainObject(obj)); //true

这个答案是无解的!

解答无解
本以为这个问题很好解决,结果深入后,发现这是一个无解的问题。原因如下:

function Person(){}; 
Person.prototype.constructor=Object; 
var person=new Person;

让我们来看一下person现在的状态:
超越Jquery_01_isPlainObject分析与重构
person和其构造函数Person唯一的联系就是其prototype链中的constructor属性。而在我们判断是否为'纯粹的对象'主要是依据对象实例的constructor进行的。如果我们将其指向Object,正如图中看到的那样,那么person和Person在代码上就没有关系了。也正是因为这一点,让类型的判断出现了问题。
Javascript 相关文章推荐
Javascript 浮点运算的问题分析与解决方法
Aug 27 Javascript
兼容主流浏览器的iframe自适应高度js脚本
Jan 10 Javascript
使用js实现关闭js弹出层的窗口
Feb 10 Javascript
谈谈encodeURI和encodeURIComponent以及escape的区别与应用
Nov 24 Javascript
JS实现响应鼠标点击动画渐变弹出层效果代码
Mar 25 Javascript
实现一个简单的vue无限加载指令方法
Jan 10 Javascript
AngularJS路由切换实现方法分析
Mar 17 Javascript
荐书|您有一份JavaScript书单待签收
Jul 21 Javascript
jQuery图片缩放插件smartZoom使用实例详解
Aug 25 jQuery
jQuery简单判断值是否存在于数组中的方法示例
Apr 17 jQuery
详解Vue项目在其他电脑npm run dev运行报错的解决方法
Oct 29 Javascript
详解Vue-cli3.X使用px2rem遇到的问题
Aug 09 Javascript
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
Oct 20 #Javascript
理解Javascript_14_函数形式参数与arguments
Oct 20 #Javascript
理解Javascript_13_执行模型详解
Oct 20 #Javascript
用jquery与css打造个性化的单选框和复选框
Oct 20 #Javascript
Jquery插件之多图片异步上传
Oct 20 #Javascript
jquery判断checkbox(复选框)是否被选中的代码
Oct 20 #Javascript
jQuery下扩展插件和拓展函数的写法(匿名函数使用的典型例子)
Oct 20 #Javascript
You might like
source.php查看源文件
2006/12/09 PHP
php修改时间格式的代码
2011/05/29 PHP
php使用curl存储cookie的示例
2014/03/31 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
PHP基于自定义函数实现的汉字转拼音功能实例
2017/09/30 PHP
javascript对JSON数据排序的3个例子
2014/04/12 Javascript
jQuery操作Table技巧大汇总
2016/01/23 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
2016/09/20 Javascript
最原始的jQuery注册验证方式
2016/10/11 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成"...")
2016/11/28 Javascript
JavaScript中捕获/阻止捕获、冒泡/阻止冒泡方法
2016/12/07 Javascript
Iscrool下拉刷新功能实现方法(推荐)
2017/06/26 Javascript
vue按需引入element Transfer 穿梭框
2017/09/30 Javascript
使用ESLint禁止项目导入特定模块的方法步骤
2019/03/04 Javascript
JS学习笔记之闭包小案例分析
2019/05/29 Javascript
vue之a-table中实现清空选中的数据
2019/11/07 Javascript
JS实现点击下拉列表文本框中出现对应的网址,点击跳转按钮实现跳转
2019/11/25 Javascript
JS代码优化的8点建议
2020/02/04 Javascript
Python实现的读取电脑硬件信息功能示例
2018/05/30 Python
Django接收自定义http header过程详解
2019/08/23 Python
python 消费 kafka 数据教程
2019/12/21 Python
Django启动时找不到mysqlclient问题解决方案
2020/11/11 Python
CSS3中的注音对齐属性ruby-align用法指南
2016/07/01 HTML / CSS
HTML5 drag和drop具体使用详解
2021/01/18 HTML / CSS
博朗(Braun)俄罗斯官方商店:德国小家电品牌
2019/09/24 全球购物
NOTINO英国:在线购买美容和香水
2020/02/25 全球购物
哈曼俄罗斯官方网上商店:Harman.club
2020/07/24 全球购物
大学生个人简历中的自我评价
2013/12/27 职场文书
施工材料员岗位职责
2014/02/12 职场文书
网络管理专业求职信
2014/03/15 职场文书
市级文明单位申报材料
2014/05/07 职场文书
司法工作人员群众路线对照检查材料思想汇报
2014/09/30 职场文书
2014年班主任德育工作总结
2014/12/05 职场文书
仓库统计员岗位职责
2015/04/14 职场文书
暑期辅导班宣传单
2015/07/14 职场文书
大学生党员暑假实践(活动总结)
2019/08/21 职场文书