超越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 相关文章推荐
代码生成器 document.write()
Apr 15 Javascript
JavaScript Chart 插件整理
Jun 18 Javascript
利用了jquery的ajax实现二级联互动菜单
Dec 02 Javascript
jquery实现简单的自动播放幻灯片效果
Jun 13 Javascript
Bootstrap中定制LESS-颜色及导航条(推荐)
Nov 21 Javascript
vue Render中slots的使用的实例代码
Jul 19 Javascript
vue动态路由实现多级嵌套面包屑的思路与方法
Aug 16 Javascript
JS数组交集、并集、差集的示例代码
Aug 23 Javascript
vue组件(全局,局部,动态加载组件)
Sep 02 Javascript
js 计数排序的实现示例(升级版)
Jan 12 Javascript
Node.js操作MongoDB数据库实例分析
Jan 19 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
Aug 14 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函数,php爱好者站推荐
2007/03/19 PHP
PHP+Ajax实现的检测用户名功能简单示例
2019/02/12 PHP
PHP强制转化的形式整理
2020/05/22 PHP
基于jquery的划词搜索实现(备忘)
2010/09/14 Javascript
jQuery登陆判断简单实现代码
2013/04/21 Javascript
js函数内变量的作用域分析
2015/01/12 Javascript
AngularJS实现网站换肤实例
2021/02/19 Javascript
jQuery获取复选框选中的当前行的某个字段的值
2017/09/15 jQuery
深入了解js原型模式
2019/05/30 Javascript
uni-app实现点赞评论功能
2019/11/25 Javascript
JS实现排行榜文字向上滚动轮播效果
2019/11/26 Javascript
three.js 利用uv和ThreeBSP制作一个快递柜功能
2020/08/18 Javascript
JavaScript代码实现简单计算器
2020/12/27 Javascript
[03:30]完美盛典趣味短片 CSGO2019年度名场面
2019/12/07 DOTA
编写同时兼容Python2.x与Python3.x版本的代码的几个示例
2015/03/30 Python
python下载文件时显示下载进度的方法
2015/04/02 Python
基于scrapy实现的简单蜘蛛采集程序
2015/04/17 Python
django启动uwsgi报错的解决方法
2018/04/08 Python
Python实现重建二叉树的三种方法详解
2018/06/23 Python
python如何生成各种随机分布图
2018/08/27 Python
python可视化实现代码
2019/01/15 Python
python matplotlib库绘制散点图例题解析
2019/08/10 Python
wxpython布局的实现方法
2019/11/01 Python
python将三维数组展开成二维数组的实现
2019/11/30 Python
pandas数据拼接的实现示例
2020/04/16 Python
只要五步 就可以用HTML5/CSS3快速制作便签贴特效(图)
2012/06/04 HTML / CSS
HTML5几个设计和修改的页面范例分享
2015/09/29 HTML / CSS
美国隐形眼镜网上商店:Lens.com
2019/09/03 全球购物
纬创Java面试题笔试题
2014/10/02 面试题
护理自荐信范文
2013/10/05 职场文书
外贸业务员求职信范文
2013/12/12 职场文书
《春晓》教学反思
2014/04/20 职场文书
查摆问题自查报告范文
2014/10/13 职场文书
2015年班主任个人工作总结
2015/03/31 职场文书
python可视化大屏库big_screen示例详解
2021/11/23 Python
vue+echarts实现多条折线图
2022/03/21 Vue.js