• 超越Jquery_01_isPlainObject分析与重构


    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现在的状态:

    person和其构造函数Person唯一的联系就是其prototype链中的constructor属性。而在我们判断是否为'纯粹的对象'主要是依据对象实例的constructor进行的。如果我们将其指向Object,正如图中看到的那样,那么person和Person在代码上就没有关系了。也正是因为这一点,让类型的判断出现了问题。 

  • 相关阅读:
    [ActionSprit 3.0] FMS直播
    Selenium学习之==>Css Selector使用方法
    Selenium学习之==>Xpath使用方法
    Selenium学习之==>WebDriver驱动对照表
    Selenium学习之==>Selenium介绍
    HTML学习之==>JS
    HTML学习之==>DOM操作
    HTML学习之==>CSS
    HTML学习之==>HTML标签
    Python学习之==>线程&&进程
  • 原文地址:https://www.cnblogs.com/fool/p/1853813.html
Copyright © 2020-2023  润新知