標籤:prototype 角度 介紹 下一步 cto ref ber target efi
原文轉自http://www.cnblogs.com/onepixel/p/5126046.html!
說到資料類型,我們先說一下JavaScript 中常見的幾種資料類型:
基本類型:string,number,boolean
特殊類型:undefined,null
參考型別:Object,Function,Function,Array,RegExp,Date,...
很多時候我們都需要通過判斷變數的資料類型來進行下一步操作,下面我們介紹常用的4種方法:
typeof ‘‘; // string 有效typeof 1; // number 有效typeof true; //boolean 有效typeof undefined; //undefined 有效typeof null; //object 無效typeof [] ; //object 無效typeof new Function(); // function 有效typeof new Date(); //object 無效typeof new RegExp(); //object 無效
typeof 可以對JS基礎資料類型做出準確的判斷,而對於參考型別返回的基本上都是object, 其實返回object也沒有錯,因為所有對象的原型鏈最終都指向了Object,Object是所有對象的`祖宗`。 但當我們需要知道某個對象的具體類型時,typeof 就顯得有些力不從心了。
2、instanceof
instanceof 是用來判斷 A 是否為 B 的執行個體對,運算式為:A instanceof B,如果A是B的執行個體,則返回true,否則返回false。 在這裡需要特別注意的是:instanceof檢測的是原型,我們用一段虛擬碼來類比其內部執行過程:
instanceof (A,B) = { var L = A.__proto__; var R = B.prototype; if(L === R) { //A的內部屬性__proto__指向B的原型對象 return true; } return false;}
從上述過程可以看出,當 A 的 __proto__ 指向 B 的 prototype 時,就認為A就是B的執行個體,我們再來看幾個例子:
[] instanceof Array; //true{} instanceof Object;//truenew Date() instanceof Date;//true function Person(){};new Person() instanceof Person; [] instanceof Object; //truenew Date() instanceof Object;//truenew Person instanceof Object;//true
我們發現,雖然 instanceof 能夠判斷出 [] 是Array的執行個體,但它認為 [] 也是Object的執行個體,為什麼呢? 我們來分析一下[]、Array、Object 三者之間的關係: 從instanceof 能夠判斷出 [].__proto__ 指向 Array.prototype, 而 Array.prototype.__proto__ 又指向了Object.prototype,Object.prototype.__proto__ 指向了null,標誌著原型鏈的結束。因此,[]、Array、Object就形成了如所示的一條原型鏈:
從原型鏈可以看出,[] 的 __proto__ 直接指向Array.prototype, 間接指向Object.prototype, 所以按照 instanceof 的判斷規則,[] 就是Object的執行個體。當然,類似的new Date()、new Person() 也會形成這樣一條原型鏈,因此,instanceof 只能用來判斷兩個對象是否屬於原型鏈的關係, 而不能擷取對象的具體類型。
3、constructor
當一個函數F被定義時,JS引擎會為F添加prototype原型,然後再在prototype上添加一個constructor屬性,並讓其指向F的引用。如下所示:
當執行 var f = new F() 時,F被當成了建構函式,f是F的執行個體對象,此時F原型上的constructor傳遞到了f上,因此f.constructor == F
可以看出,JS在函數F的原型上定義了constructor,當F被當作建構函式用來建立對象時,建立的新對象就被標記為了“F” 類型,使得新對象有名有姓,可以追溯。
同理,JS中的資料類型也遵守這個規則:
細節問題:
- null和undefined是無效的對象,因此是不會有constructor存在的,這兩種類型的資料需要通過typeof來判斷。
- JS對象的constructor是不穩定的,這個主要體現在自訂對象上,當開發人員重寫prototype後,原有的constructor會丟失,constructor會預設為Object
為什麼變成了Object?
prototype被重新賦值的是一個{}, {}是new Object()的字面量,因此new Object()會將Object原型上的constructor傳遞給{},也就是Object本身。
因此,為了規範,在重寫對象原型時一般都需要重新給constructor賦值,以保證執行個體對象的類型不被改寫。
4、Object.prototype.toString
toString是Object原型對象上的一個方法,該方法預設返回其調用者的具體類型,更嚴格的講,是 toString運行時this指向的物件類型, 返回的類型格式為[object,xxx],xxx是具體的資料類型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有對象的類型都可以通過這個方法擷取到。
Object.prototype.toString.call(‘‘) ; // [object String]Object.prototype.toString.call(1) ; // [object Number]Object.prototype.toString.call(true) ; // [object Boolean]Object.prototype.toString.call(undefined) ; // [object Undefined]Object.prototype.toString.call(null) ; // [object Null]Object.prototype.toString.call(new Function()) ; // [object Function]Object.prototype.toString.call(new Date()) ; // [object Date]Object.prototype.toString.call([]) ; // [object Array]Object.prototype.toString.call(new RegExp()) ; // [object RegExp]Object.prototype.toString.call(new Error()) ; // [object Error]Object.prototype.toString.call(document) ; // [object HTMLDocument]Object.prototype.toString.call(window) ; //[object global] window是全域對象global的引用
需要注意的是,必須通過Object.prototype.toString.call來擷取,而不能直接 new Date().toString(), 從原型鏈的角度講,所有對象的原型鏈最終都指向了Object, 按照JS變數尋找規則,其他對象應該也可以直接存取到Object的toString方法,而事實上,大部分的對象都實現了自身的toString方法,這樣就可能會導致Object的toString被終止尋找,因此要用call來強制執行Object的toString方法。
判斷JS資料類型的幾種方法