超越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中的变量是传值还是传址的?
Apr 19 Javascript
使用AngularJS来实现HTML页面嵌套的方法
Jun 17 Javascript
javascript实现简单计算器效果【推荐】
Apr 19 Javascript
微信小程序 后台https域名绑定和免费的https证书申请详解
Nov 10 Javascript
详解基于javascript实现的苹果系统底部菜单
Dec 02 Javascript
JS前端笔试题分析
Dec 19 Javascript
jQuery实现给input绑定回车事件的方法
Feb 09 Javascript
webpack使用 babel-loader 转换 ES6代码示例
Aug 21 Javascript
Angular使用动态加载组件方法实现Dialog的示例
May 11 Javascript
layui问题之渲染数据表格时,仅出现10条数据的解决方法
Sep 12 Javascript
将Vue组件库更换为按需加载的方法步骤
May 06 Javascript
js实现限定范围拖拽的示例
Oct 26 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
joomla内置的表单验证功能使用方法
2010/06/11 PHP
用Php编写注册后Email激活验证的实例代码
2013/03/11 PHP
PHP开发api接口安全验证操作实例详解
2020/03/26 PHP
JS获得URL超链接的参数值实例代码
2013/06/21 Javascript
js文本框输入点回车触发确定兼容IE、FF等
2013/11/19 Javascript
Javascript 运动中Offset的bug解决方案
2014/12/24 Javascript
Jquery 垂直多级手风琴菜单附源码下载
2015/11/17 Javascript
Angularjs根据json文件动态生成路由状态的实现方法
2017/04/17 Javascript
vue.js开发环境搭建教程
2017/05/04 Javascript
React Native悬浮按钮组件的示例代码
2018/04/05 Javascript
JavaScript错误处理操作实例详解
2019/01/04 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
关于Layui Table隐藏列问题
2019/09/16 Javascript
javascript实现前端分页效果
2020/06/24 Javascript
Vue和React有哪些区别
2020/09/12 Javascript
vue仿携程轮播图效果(滑动轮播,下方高度自适应)
2021/02/11 Vue.js
[01:06]欢迎来到上海,TI9
2018/08/26 DOTA
Python中循环引用(import)失败的解决方法
2018/04/22 Python
用python处理MS Word的实例讲解
2018/05/08 Python
详解python单元测试框架unittest
2018/07/02 Python
Python3.6中Twisted模块安装的问题与解决
2019/04/15 Python
详解python中的index函数用法
2019/08/06 Python
python爬虫 基于requests模块的get请求实现详解
2019/08/20 Python
Python如何实现强制数据类型转换
2019/11/22 Python
django 实现手动存储文件到model的FileField
2020/03/30 Python
目前不被任何主流浏览器支持的CSS3属性汇总
2014/07/21 HTML / CSS
Canvas系列之滤镜效果
2019/02/12 HTML / CSS
webView加载html图片遇到的问题解决
2019/10/08 HTML / CSS
会计出纳员的自我评价
2014/01/15 职场文书
项目建议书范文
2014/05/12 职场文书
验房委托书
2014/08/30 职场文书
未婚证明书模板
2014/10/08 职场文书
李强优秀员工观后感
2015/06/16 职场文书
浙江省杭州市平均工资标准是多少?
2019/07/09 职场文书
Python学习之迭代器详解
2022/04/01 Python
Apache Hudi 加速传统的批处理模式
2022/04/24 Servers