超越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 相关文章推荐
Chrome中JSON.parse的特殊实现
Jan 12 Javascript
牛叉的Jquery——Jquery与DOM对象的互相转换及DOM的三种操作
Oct 29 Javascript
node.js连接mongoDB数据库 快速搭建自己的web服务
Apr 17 Javascript
jQuery+Ajax实现限制查询间隔的方法
Jun 07 Javascript
javascript js 操作数组 增删改查的简单实现
Jun 20 Javascript
WEB开发之注册页面验证码倒计时代码的实现
Dec 15 Javascript
Javascript中常用类型的格式化方法小结
Dec 26 Javascript
JS实现旋转木马式图片轮播效果
Jan 18 Javascript
原生JavaScript来实现对dom元素class的操作方法(推荐)
Aug 16 Javascript
vue项目中定义全局变量、函数的几种方法
Nov 08 Javascript
vue 插槽简介及使用示例
Nov 19 Vue.js
JavaScript 异步时序问题
Nov 20 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字符串截取的简单方法
2013/07/04 PHP
yii2 commands模式以及配置crontab定时任务的方法
2017/08/19 PHP
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
2010/12/08 Javascript
查看图片(前进后退)功能实现js代码
2013/04/24 Javascript
Javascript Object 对象学习笔记
2014/12/17 Javascript
js图片轮播效果实现代码
2020/04/18 Javascript
动态加载js文件简单示例
2016/04/21 Javascript
jQuery+php实时获取及响应文本框输入内容的方法
2016/05/24 Javascript
用NodeJS实现批量查询地理位置的经纬度接口
2016/08/16 NodeJs
JavaScript判断浏览器及其版本信息
2017/01/20 Javascript
详解原生js实现offset方法
2017/06/15 Javascript
nodejs 图解express+supervisor+ejs的用法(推荐)
2017/09/08 NodeJs
JavaScript实现二叉树定义、遍历及查找的方法详解
2017/12/20 Javascript
vue-rx的初步使用教程
2018/09/21 Javascript
100行代码实现一个vue分页组功能
2018/11/06 Javascript
JavaScript数组常用的增删改查与其他属性详解
2020/10/13 Javascript
一篇文章让你搞懂JavaScript 原型和原型链
2020/11/23 Javascript
[01:40]2014DOTA2国际邀请赛 三冰SOLO赛后采访恶搞
2014/07/09 DOTA
python之wxPython应用实例
2014/09/28 Python
在Python中使用判断语句和循环的教程
2015/04/25 Python
Windows下Eclipse+PyDev配置Python+PyQt4开发环境
2016/05/17 Python
Python机器学习算法之k均值聚类(k-means)
2018/02/23 Python
Python实现的在特定目录下导入模块功能分析
2019/02/11 Python
PYQT5实现控制台显示功能的方法
2019/06/25 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
python 非线性规划方式(scipy.optimize.minimize)
2020/02/11 Python
django rest framework serializers序列化实例
2020/05/13 Python
Python如何输出整数
2020/06/07 Python
python 实现有道翻译功能
2021/02/26 Python
CSS3+DIV实现漂亮的动画彩色标签
2016/06/16 HTML / CSS
Dockers鞋官网:Dockers Shoes
2018/11/13 全球购物
快递业务员岗位职责
2014/01/06 职场文书
《七颗钻石》教学反思
2014/02/28 职场文书
2015年毕业生个人自荐书
2015/03/24 职场文书
地道战观后感
2015/06/04 职场文书
yolov5返回坐标的方法实例
2022/03/17 Python