超越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 相关文章推荐
多个iframe自动调整大小的问题
Sep 18 Javascript
jQuery 关于伪类选择符的使用说明
Apr 24 Javascript
js实现简单登录功能的实例代码
Nov 09 Javascript
Javascript封装DOMContentLoaded事件实例
Jun 12 Javascript
JavaScript创建闭包的两种方式的优劣与区别分析
Jun 22 Javascript
js实现图片缓慢放大缩小效果
Aug 02 Javascript
js字符限制(字符截取) 一个中文汉字算两个字符
Sep 12 Javascript
jQuery 禁止表单用户名、密码自动填充功能
Oct 30 jQuery
一次记住JavaScript的6个正则表达式方法
Feb 22 Javascript
详解Vue CLI3配置解析之css.extract
Sep 14 Javascript
解决vue项目刷新后,导航菜单高亮显示的位置不对问题
Nov 01 Javascript
vue backtop组件的实现完整代码
Apr 07 Vue.js
理解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
BBS(php & mysql)完整版(五)
2006/10/09 PHP
用php实现像JSP,ASP里Application那样的全局变量
2007/01/12 PHP
php的数组与字符串的转换函数整理汇总
2013/07/18 PHP
php中使用base HTTP验证的方法
2015/04/20 PHP
php排序算法实例分析
2016/10/17 PHP
PHP实现生成模糊图片的方法示例
2017/12/21 PHP
js css样式操作代码(批量操作)
2009/10/09 Javascript
JavaScript的parseInt 取整使用
2011/05/09 Javascript
Bootstrap零基础入门教程(二)
2016/07/18 Javascript
微信小程序 Image API实例详解
2016/09/30 Javascript
解决vue2.x中数据渲染以及vuex缓存的问题
2017/07/13 Javascript
node.js 用socket实现聊天的示例代码
2017/10/17 Javascript
JavaScript实现的DOM树遍历方法详解【二叉DOM树、多叉DOM树】
2018/05/07 Javascript
Vue+Koa2 打包后进行线上部署的教程详解
2019/07/31 Javascript
JsonProperty 的使用方法详解
2019/10/11 Javascript
Vue简单封装axios之解决post请求后端接收不到参数问题
2020/02/16 Javascript
Javascript ParentNode和ChildNode接口原理解析
2020/03/16 Javascript
[01:33]完美世界DOTA2联赛PWL S3 集锦第二期
2020/12/21 DOTA
python生成指定尺寸缩略图的示例
2014/05/07 Python
Python3中详解fabfile的编写
2018/06/24 Python
Python开发最牛逼的IDE——pycharm
2018/08/01 Python
PyQt5实现五子棋游戏(人机对弈)
2020/03/24 Python
python 循环数据赋值实例
2019/12/02 Python
keras多显卡训练方式
2020/06/10 Python
在keras里面实现计算f1-score的代码
2020/06/15 Python
Python中常用的os操作汇总
2020/11/05 Python
CSS3混合模式mix-blend-mode/background-blend-mode简介
2018/03/15 HTML / CSS
css3中检验表单的required,focus,valid和invalid样式
2014/02/21 HTML / CSS
移动web模拟客户端实现多方框输入密码效果【附代码】
2016/03/25 HTML / CSS
John Varvatos官方网站:设计师男士时装
2017/02/08 全球购物
写出程序把一个链表中的接点顺序倒排
2014/04/28 面试题
舞蹈教师自荐信
2014/01/27 职场文书
爱护草坪标语
2014/06/24 职场文书
中国梦演讲稿3分钟
2014/08/19 职场文书
保管员岗位职责
2015/02/14 职场文书
Python开发五子棋小游戏
2022/05/02 Python