1. 程式人生 > 其它 >typeof 和 instanceof講解以及最佳型別判斷實踐

typeof 和 instanceof講解以及最佳型別判斷實踐

技術標籤:返璞歸真javascriptjavascript

說在前面

JavaScript作為前端當家的語言,其重要程度不言而喻,一些基礎的語法以及概念之前經常有看,但是隨看隨忘,過程中有一些自己覺得驚鴻一瞥的發現也隨著時間消失不見,特此開一個專題,把往往種種的體會分享出來,供自己回顧以及各位拿取。

開門見山

其實在閱讀一些原始碼或者封裝的程式碼時,經常會看到 使用 typeof 或者 instanceof來進行一些判斷,有時不能很好地理解判斷的具體含義,下面通過分析這兩者的使用方式以及自身特性來加強理解。

typeof

語法: typeof operand 後面可以緊跟表示物件或者原始值的表示式

,他會返回表示式的型別。

那麼他判斷的所有型別都是準確無誤的嘛?或者說,他返回的型別都是我們想看到的嗎?顯然不是,比如JavaScript最初設計中的一個小“瑕疵”,

typeof null   // 'object'

我們不能說他錯,但是我們在實際使用的過程中可不希望把null 判斷成為一個object,因為這樣會導致一些嚴重的錯誤。

用一句簡單的話來說 typeof可以準確的判斷結果不為 object的型別的資料,別急,後面我們會印證這個觀點。

下面我們一起來看一下typeof關鍵字在判斷型別時的一些表現:

typeof 37               // 'number'
typeof Nan              // 'number' 注意,特殊型別的number,not a number的number
typeof true // 'boolean' typeof '1' // 'string' typeof String('1') // 'string' typeof Symbol() // 'symbol' typeof undefined // 'undefined' typeof function() {} // 'function' typeof {a: 1} // 'object' 一直到這裡,所有得到的資料型別都是我們想得到的 ------------------------------
------------------我是分界線-------------------------------------------- var a = [1,2,3] typeof a // 'object', 陣列是一種特殊的物件,判斷是否為陣列,需要使用Array.isArray方法 typeof null // 'object' 可以通過 operand === null 判斷是否為 null typeof new Date() // 'object' typeof new String('a') // 'object',如果你列印過控制檯的資訊,你會看到得到的結果是 String {"a"},確實展示形式是物件,但是我們使用 // 過程中會將其理解為字串(當然他在使用過程中和字串無異,但是他在記憶體中確實是以String {"a"}存在)

從上述例子中可以看出typeof對於一些建立型別的資料(使用了new 關鍵字)都會返回 object,雖說返回了記憶體中正確的存在形式,但結果可能並不是我們想要得到的。所以說 typeof關鍵字,返回的不為 object型別的資料都是準確的,但是對於返回型別為 object 的資料,我們需要斟酌一下實際的結果。

延伸一刻:如果我們想判斷一個數據表示式是否為object型別,要如何判斷?

// we got a referance named a
if (typeof a !== null && typeof a === 'object') {
    return true
}

唉? 剛才不是說typeof 判斷的型別為object的不準嗎?怎麼現在又這樣寫呢?其實根據上述結果,new String('123')雖然我們想得到的結果是string,但是說他是一個object卻沒有任何問題!

instanceof

語法: object instanceof constructor 用來檢測constructor.protype 是否 存在於引數 object的原型鏈上。一定注意,後面跟的是一個建構函式。

一言以蔽之:可以準確判斷複雜引用的資料型別,但不能正確判斷基礎資料型別。

var d = new Date()
d instanceof Date     // true
var s = new String('cctv')
s instanceof String   // true  s在控制檯打印出來的結果是 String{"cctv"}
var str = 'cctv'
str instanceof String // false 這是怎麼回事?  參見下方分析。
Object.getPrototypeOf(str) === String.prototype  
// true  確實符合了概念,看似存在於str的原型鏈上,但是str自身並不是一個 object

由此可以判斷,instanceof在內部實現中,會判斷 instanceof左側是否為 object。如果不是,返回 false

再有,原型鏈是具有傳遞性的:

function C() {}

var o = new C();
o instanceof C  // true  Object.getPrototypeOf(o) === C.prototype
C.prototype instanceof Object  // true Object.getPrototypeof(C.prototype) === Object.prototype
o instanceof Object  // true  原型鏈的傳遞性

由此可以分析得出,原生js在實現 instanceof 的時候,會迴圈遍歷左側objectObject.getPrototypeOf('object')屬性,並與 constructor.prototype進行對比,如果相等,則返回 true,如果不相等則繼續排查,直到 Object.getPrototypeOf('object')的結果為 null 則返回 false

綜上二者提出的概念,可以簡單的實現一個 自己的instanceof,網上例子很多,這裡不貼程式碼了,根據我的經驗,貼上來程式碼大家很少會自己實踐,just try it.

最佳型別判斷實踐

可曾聽聞十三太保之 toString,這是個很神奇的方法,每個物件都繼承了來自object的這個是屬性,他可以被重寫來完成一些特殊的任務,這裡主要介紹他的預設用法,返回 [object class],其中class是該物件的類,可以為 Object,Number,Function,Date,Window,HTMLDocument等。

function getType(obj){
  // 對於typeof返回結果是object的,再進行如下的判斷,正則返回結果
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); 
}
getType(window) // Window
getType(new Date()) // Date
getType(document)  // HTMLDocument

參考網站:

typeof - JavaScript | MDN

instanceof - JavaScript | MDN