现在的位置: 首页 > 综合 > 正文

判断是否是纯粹的对象-isPlainObject

2012年02月02日 ⁄ 综合 ⁄ 共 2595字 ⁄ 字号 评论关闭

需求:
有时候我想限定参事是一个对象,形如{a:1,b:2}类似于json格式。但是js中没有什么方法判断纯粹对象这个方法。
js中一切都是对象,数字可以是Number对象,还有其他dom对象等等。typeof location,Object.toString.call(document)在ie下 都返回了object
我们想要这样一个对象,他是个字面量,形如var o={a:1,b:2}.或者他是这样生成的var o=new Object();o.a=1;o.b=2;对于这样的构造函数为Object的对象o,才是满足我们要求的纯粹的对象。看下面jquery对纯粹对象的判断

实现:
jquery1.64中的

 1     isPlainObject: function( obj ) {
2 // Must be an Object.
3 // Because of IE, we also have to check the presence of the constructor property.
4 // Make sure that DOM nodes and window objects don't pass through, as well
5 //首先去除非对象,window对象,因为ie的dom返回的是object这里jquery的type函数不能去掉dom对象,只能去除一些带有nodeType的对象
6 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
7 return false;
8 }
9 //constructor属性是一个可以修改的值,这里通过constructor来判断是不靠谱的
10 //如果是正常情况下,不修改constructor,这里先判断有constructor,
11 //并且constructor不在对象自身里(一般情况下对象自身都不含constructor属性,constructor都在构造函数的prototype中定义)
12 //再判断对象的构造函数的prototype中没有isPrototypeOf,只有构造函数是Object的情况下,才会拥有isPrototypeOf方法。
13 //反过来说这里的判断逻辑是这样的,如果对象没有constructor属性,或者对象的constructor是自身的属性(对象只能是构造函数的prototype),或者对象的构造函数是Object的情况
14 try {
15 // Not own constructor property must be Object
16 if ( obj.constructor &&
17 !hasOwn.call(obj, "constructor") &&
18 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
19 return false;
20 }
21 } catch ( e ) {
22 // IE8,9 Will throw exceptions on certain host objects #9897
23 return false;
24 }
25
26 // Own properties are enumerated firstly, so to speed up,
27 // if last one is own, then all properties are own.
28 //for in 枚举了obj的所有属性。ff系列会首先枚举自身的属性,但是ie系列并不是。所以下面的通过最后一个属性来判断并不对啊
29 var key;
30 for ( key in obj ) {}
31
32 return key === undefined || hasOwn.call( obj, key );
33 },

行6中。因为ie的问题,并不能去除一些dom,比如location。不过可以限制Object
行14中。因为constructor的可变性,判断不靠谱.不过正常情况下,一般不会手动修改constructor
行29中。for in遍历就是个错误,ff下可行,ie下根本就不对。

淘宝kissy中的实现

 1             isPlainObject:function (o) {
2 /**
3 * note by yiminghe
4 * isPlainObject(node=document.getElementById("xx")) -> false
5 * toString.call(node) : ie678 == '[object Object]',other =='[object HTMLElement]'
6 * 'isPrototypeOf' in node : ie678 === false ,other === true
7 * refer http://lifesinger.org/blog/2010/12/thinking-of-isplainobject/
8 */
9 return o && toString.call(o) === '[object Object]' && 'isPrototypeOf' in o;
10 },

这个实现过于简单了。这里如果是new function(){}的对象,这里可以通过

Qwrap中的实现

 1     function getConstructorName(o) { 
2 //加o.constructor是因为IE下的window和document
3 if(o != null && o.constructor != null){
4 return Object.prototype.toString.call(o).slice(8, -1);
5 }else{
6 return '';
7 }
8 }
9 isPlainObject: function(obj) {
10 return getConstructorName(obj) == 'Object';
11 },

这里的实现也有问题。从这里看出一般的框架中都没有给出一个完美的实现方法。

总结
综上看来,jquery实现的其实还是考虑比较全面的。但是因为js语言本身没有什么办法判断,所以只能约定好多写注释。
不过我们也可以总结下已有的判断方式如下
1通过constructor和isPrototypeOf判断。
  constructor必须是Object,且isPrototypeOf是.constructor的ownProperty。
2通过for in遍历来判断。
  这个是最靠谱但是又最影响性能的判断
  通过遍历出所有属性,判断是否是ownProperty
  

抱歉!评论已关闭.