超越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的弹出框插件
Mar 18 Javascript
用按钮控制iframe显示的网页实现方法
Feb 04 Javascript
Jquery post传递数组方法实现思路及代码
Apr 28 Javascript
web网页按比例显示图片实现原理及js代码
Aug 09 Javascript
javascript学习笔记(四)function函数部分
Sep 30 Javascript
angular2使用简单介绍
Mar 01 Javascript
判断js的Array和Object的实现方法
Aug 29 Javascript
通过修改360抢票的刷新频率和突破8车次限制实现方法
Jan 04 Javascript
js图片延迟加载(Lazyload)三种实现方式
Mar 01 Javascript
js正则表达式验证表单【完整版】
Mar 06 Javascript
vue 设置 input 为不可以编辑的实现方法
Sep 19 Javascript
原生JS实现pc端轮播图效果
Dec 21 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
二次元帅气男生排行榜,只想悄悄收藏系列
2020/03/04 日漫
jQuery EasyUI API 中文文档 - DateBox日期框
2011/10/15 PHP
PHP中对数组的一些常用的增、删、插操作函数总结
2015/11/27 PHP
WordPress中用于获取文章信息以及分类链接的函数用法
2015/12/18 PHP
PHP实现websocket通信的方法示例
2018/08/28 PHP
通过PHP实现用户注册后邮箱验证激活
2020/11/10 PHP
基于jquery实现的上传图片及图片大小验证、图片预览效果代码
2011/04/12 Javascript
Knockoutjs快速入门(经典)
2012/12/24 Javascript
js 自动播放的实例代码
2013/11/19 Javascript
JavaScript中的分号插入机制详细介绍
2015/02/11 Javascript
JavaScript使用yield模拟多线程的方法
2015/03/19 Javascript
JS iFrame加载慢怎么解决
2016/05/13 Javascript
JS中使用变量保存arguments对象的方法
2016/06/03 Javascript
Vue.js动态添加、删除选题的实例代码
2016/09/30 Javascript
ReactNative列表ListView的用法
2017/08/02 Javascript
Nodejs+angularjs结合multiparty实现多图片上传的示例代码
2017/09/29 NodeJs
你应该知道的几类npm依赖包管理详解
2017/10/06 Javascript
老生常谈JavaScript面向对象基础与this指向问题
2017/10/16 Javascript
Angularjs实现控制器之间通信方式实例总结
2018/03/27 Javascript
vue中的inject学习教程
2019/04/24 Javascript
Angular实现svg和png图片下载实现
2019/05/05 Javascript
使用xampp将angular项目运行在web服务器的教程
2019/09/16 Javascript
js单线程的本质 Event Loop解析
2019/10/29 Javascript
利用python操作SQLite数据库及文件操作详解
2017/09/22 Python
详解Python中pandas的安装操作说明(傻瓜版)
2019/04/08 Python
python数据挖掘需要学的内容
2019/06/23 Python
python和php哪个容易学
2020/06/19 Python
python实现经典排序算法的示例代码
2021/02/07 Python
小学生自我鉴定
2013/10/12 职场文书
项目专员岗位职责
2013/12/04 职场文书
水利局群众路线专题民主生活会发言材料
2014/09/21 职场文书
事业单位人员的自我评价范文
2014/09/21 职场文书
2015年“七七卢沟桥事变”纪念活动总结
2015/03/24 职场文书
2016年第16个全民国防教育日宣传活动总结
2016/04/05 职场文书
python spilt()分隔字符串的实现示例
2021/05/21 Python
Windows Server 版本 20H2 于 8 月 9 日停止支持,Win10 版本 21H1 将于 12 月结束支
2022/07/23 数码科技