JS基本觀念:typeof vs instanceof
在寫程式時難免會要對變數型別做判斷,舉例像是在寫api時,這時要把使用者想得越機車越好,因為你不能預料到他會不會臨機一動就給你來個你沒想過的參數(因為我自己也是XD),所以這邊來聊一下在 javascript 裡面常用到的兩個功能,typeof 以及 instanceof。
1. typeof
typeof
就是用來判斷參數是什麼型別,用法很簡單,就typeof A
。
回傳值基本上就是常見的js data type:
"number", "string", "boolean", "object", "function", "undefined", "symbol", "bigint"
以下來看些簡單例子吧!
// Number
typeof 10
typeof 3.14
typeof Infinity
typeof typeof NaN // String
typeof ''
typeof 'abc' // Boolean
typeof true
typeof !!(1) // Undefined
typeof undefined
typeof declaredButUndefinedVariable //宣告但沒賦值
typeof undeclaredVariable //未宣告// Object
typeof {a: 1}
typeof null
typeof new Date()
typeof new RegExp()
// 以下用法比較少見,但他的確會被判定成object
typeof new Boolean(true)
typeof new Number(1)
typeof new String('abc')// function
typeof function() {}
typeof Math.sin
typeof class C {}
小結
- 對primitive type(string, number等object外)類型的判斷回傳值都挺正確的,除了null外
- 對於object,除了function外,其他一律回傳object
- 對於null,回傳object
- 對於function,回傳function
至於為何null會這麼特別
In the first implementation of JavaScript, JavaScript values were represented as a type tag and a value. The type tag for objects was 0.
null
was represented as the NULL pointer (0x00 in most platforms). Consequently, null had 0 as type tag, hence the "object"typeof
return value. (reference)
2. instanceof
instanceof 是用來判斷 A是否為B的實例,比較的是原型(prototype)。用法:
object instanceof constructor// object: The object to test.
// constructor:Function to test against
故若constructor.prototype存在於object的原型鍊(prototype chain)裡面,則回傳true,否則false。
下面來舉個例子說明吧!
function C() {}
function D() {}
var o = new C();
// true, 因為C在o的原型鍊內 ; o.__proto__ === C.prototype
o instanceof C;
// false, 因為 D.prototype 不存在在 o 的原型鍊
o instanceof D;// true 因為object存在於o的原型鍊
// o.__proto__.__proto__ === Object.prototype
o instanceof Object;
這邊我們來把o的原型鍊給畫出來會更容易理解!
從原型鍊中可以看到,o指到C.prototype而又間接的指到Object.prototype,所以依照instanceof
的規則,o是Object的一個實例。依此類推,類似new Date()
, new RegExp()
等等也會形成一條類似的原型鍊。因此,instanceof
只能用來判斷兩個比較對象是否屬於實例關係,無法明確指出具體屬於哪種類型。
小結
- 畫出原型鍊(prototype chain)吧!一切就會很明瞭啦。
toString()
延續上面提到的instanceof
無法明確指出屬於哪種類型,我們可以利用Object原生提供的toString()方法來得到類型。使用call
或apply
來呼叫該方法可以得到呼叫者的類型,格式為[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(Symbol()); //[object Symbol]
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]