超越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 相关文章推荐
Discuz! 6.1_jQuery兼容问题
Sep 23 Javascript
JavaScript学习笔记(一) js基本语法
Oct 25 Javascript
jquery索引在使用中的一些困惑
Oct 24 Javascript
jquery 日期控件datepicker属性详细解析
Nov 08 Javascript
$.extend 的一个小问题
Jun 18 Javascript
图解JavaScript中的this关键字
May 28 Javascript
关于原生js中bind函数的简单实现
Aug 10 Javascript
jQuery实现带延时功能的水平多级菜单效果【附demo源码下载】
Sep 21 Javascript
基于JS快速实现导航下拉菜单动画效果附源码下载
Oct 27 Javascript
浅谈EasyUI常用控件的禁用方法
Nov 09 Javascript
详解vue 命名视图
Aug 14 Javascript
微信小程序上传图片并等比列压缩到指定大小的实例代码
Oct 24 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中的phpinfo()函数
2013/06/06 PHP
php中的四舍五入函数代码(floor函数、ceil函数、round与intval)
2014/07/14 PHP
php获取远程文件大小
2015/10/20 PHP
基于命令行执行带参数的php脚本并取得参数的方法
2016/01/25 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
2016/09/09 PHP
php cookie用户登录的详解及实例代码
2017/01/03 PHP
PHP获取ttf格式文件字体名的方法示例
2019/03/06 PHP
js直接编辑当前cookie的脚本
2008/09/14 Javascript
jQuery中live方法的重复绑定说明
2011/10/21 Javascript
JQuery调用绑定click事件的3种写法
2015/03/28 Javascript
Jqgrid之强大的表格插件应用
2015/12/02 Javascript
jQuery 3.0 的变化及使用方法
2016/02/01 Javascript
js多个物体运动功能实例分析
2016/12/20 Javascript
Angular.JS实现无限级的联动菜单(使用demo)
2017/02/08 Javascript
jQuery Validate 相关参数及常用的自定义验证规则
2017/03/06 Javascript
vue-resource调用promise取数据方式详解
2017/07/21 Javascript
JS实现的邮箱提示补全效果示例
2018/01/30 Javascript
Vue中Axios从远程/后台读取数据
2019/01/21 Javascript
jquery实现淡入淡出轮播图效果
2020/12/13 jQuery
微信小程序实现简单购物车功能
2020/12/30 Javascript
[01:10:16]DOTA2上海特级锦标赛B组资格赛#2 Fnatic VS Spirit第一局
2016/02/27 DOTA
[39:53]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第一场 11.19
2020/11/19 DOTA
Django 日志配置按日期滚动的方法
2019/01/31 Python
浅谈pytorch torch.backends.cudnn设置作用
2020/02/20 Python
python中setuptools的作用是什么
2020/06/19 Python
Python使用eval函数执行动态标表达式过程详解
2020/10/17 Python
精彩自我鉴定
2014/01/16 职场文书
优秀共产党员先进事迹
2014/01/27 职场文书
3.12植树节活动总结2014
2014/03/13 职场文书
幼儿教师求职信
2014/05/24 职场文书
2015年妇产科工作总结
2015/05/18 职场文书
公司开业主持词
2015/07/02 职场文书
六一亲子活动感想
2015/08/07 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS
Android studio 简单计算器的编写
2022/05/20 Java/Android
详解Spring Bean的配置方式与实例化
2022/06/10 Java/Android