超越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 相关文章推荐
JQuery 技巧和窍门整理(8个)
Apr 22 Javascript
Webkit的跨域安全问题说明
Sep 13 Javascript
Js四则运算函数代码
Jul 21 Javascript
JS+ACTIVEX实现网页选择本地目录路径对话框
Mar 18 Javascript
JS制作手机端自适应缩放显示
Jun 11 Javascript
jQuery实现选项卡切换效果简单演示
Dec 09 Javascript
jQuery实现HTML表格单元格的合并功能
Apr 06 Javascript
jquery实现简单Tab切换菜单效果
Jul 17 Javascript
JavaScript SHA1加密算法实现详细代码
Oct 06 Javascript
jquery轻量级数字动画插件countUp.js使用详解
Oct 17 jQuery
JavaScript设计模式--桥梁模式引入操作实例分析
May 23 Javascript
wepy--用vantUI 实现上弹列表并选择相应的值操作
Nov 03 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
PHP代码保护--Zend Guard的使用详解
2013/06/03 PHP
php数组删除元素示例
2014/03/21 PHP
php根据年月获取当月天数及日期数组的方法
2016/11/30 PHP
php session的应用详细介绍
2017/03/22 PHP
JS backgroundImage控制
2009/05/19 Javascript
js隐藏与显示回到顶部按钮及window.onscroll事件应用
2013/01/25 Javascript
jQuery 鼠标经过(hover)事件的延时处理示例
2014/04/14 Javascript
让javascript加载速度倍增的方法(解决JS加载速度慢的问题)
2014/12/12 Javascript
js的回调函数详解
2015/01/05 Javascript
jQuery遍历页面所有CheckBox查看是否被选中的方法
2015/04/14 Javascript
Angularjs实现带查找筛选功能的select下拉框示例代码
2016/10/04 Javascript
jquery移除了live()、die(),新版事件绑定on()、off()的方法
2016/10/26 Javascript
vue项目配置同一局域网可使用ip访问的操作
2020/10/23 Javascript
[00:27]DOTA2次级职业联赛 - Lilith战队宣传片
2014/12/01 DOTA
[02:17]2016国际邀请赛中国区预选赛VG战队领队采访
2016/06/26 DOTA
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
python网络编程学习笔记(五):socket的一些补充
2014/06/09 Python
详解Python编程中包的概念与管理
2015/10/16 Python
Python爬虫天气预报实例详解(小白入门)
2018/01/24 Python
python traceback捕获并打印异常的方法
2018/08/31 Python
解决python ogr shp字段写入中文乱码的问题
2018/12/31 Python
python gensim使用word2vec词向量处理中文语料的方法
2019/07/05 Python
Django集成celery发送异步邮件实例
2019/12/17 Python
Python环境下安装PyGame和PyOpenGL的方法
2020/03/25 Python
在pycharm中debug 实时查看数据操作(交互式)
2020/06/09 Python
Html5游戏开发之乒乓Ping Pong游戏示例(三)
2013/01/21 HTML / CSS
香蕉共和国Banana Republic官网:美国GAP旗下偏贵族风格服饰品牌
2016/11/21 全球购物
新教师岗前培训方案
2014/06/05 职场文书
班子四风对照检查材料
2014/08/21 职场文书
买卖合同协议书范本
2014/10/18 职场文书
小学生安全保证书
2015/05/09 职场文书
2015年电信员工工作总结
2015/05/26 职场文书
男方家长婚礼致辞
2015/07/27 职场文书
预备党员入党感想
2015/08/10 职场文书
详解MySQL事务的隔离级别与MVCC
2021/04/22 MySQL
Nginx如何限制IP访问只允许特定域名访问
2022/07/23 Servers