DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> 超越Jquery_01_isPlainObject分析與重構
超越Jquery_01_isPlainObject分析與重構
編輯:關於JavaScript     

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在代碼上就沒有關系了。也正是因為這一點,讓類型的判斷出現了問題。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved