前端開發系列037-基礎篇之型別檢測
title: '前端開發系列037-基礎篇之型別檢測'
tags:
- javaScript系列
categories: []
date: 2017-09-18 20:22:13
本文介紹 JavaScript 中的資料型別,以及這些資料的型別檢測方式。
JavaScript 存在很多中資料型別,按照一貫的區分方式,我們把這些資料型別分為兩大類,分別是原始(基本)資料型別和物件型別。
其中基本( 原始 )資料型別有6種,分別是 null undefined boolean string number symbol
,物件型別則為object
,物件型別中包含Object、Array、RegExp、Function、Error、Set、Map、WeakMap
在JavaScript 程式碼中我們經常需要對資料的型別進行檢查,檢查資料型別的方式主要有四種:
- typeof 關鍵字
- instanceof 關鍵字
- Object.prototype.toString.call()
- constructor 構造器屬性
typeof 關鍵字
typeof
關鍵字是檢查資料型別最簡單也最常用的方法。
console.log(typeof "abc") /* string */ console.log(typeof 12345) /* number */ console.log(typeof true) /* boolean */ console.log(typeof undefined) /* undefined */ console.log(typeof Symbol()) /* symbol */ console.log(typeof null) /* object */ console.log(typeof typeof typeof Symbol()) /* string */ console.log(typeof {}) /* object */ console.log(typeof []) /* object */ console.log(typeof /abc/) /* object */ console.log(typeof function(){}) /* function */
我們在使用typeof
關鍵字的時候,有一些注意點。
首先就是 typeof null
得到的結果為object
而非null
,這在 JavaScript 語言中被認為(承認)是一個設計錯誤,typeof null
被判定為 object
的原因在於 null
本身表示什麼都沒有,所以在計算機中表示為一串0,而計算機內部處理的時候如果讀取的資料總是以000
開頭,那麼就將被認為是物件型別的資料。
其次,typeof
關鍵字在物件型別進行運算的時候得到的都是object
,只有函式型別比較特殊得到的是function
,也就是說我們無法通過該關鍵字來檢查給定的資料是否是陣列、或者是正則表示式等等。如果需要獲取這些結構的資料型別,或者說是獲取這些資料的建構函式,常用的方式是借用 Object 原型物件上面的 toString 方法來實現,該方法總是會返回一個[object 建構函式]
JavaScript 語言中的Object.prototype.toString
方法總是會返回[object 建構函式]
結構的字串,其中方括號中前面的object
表明該資料是物件型別的,後面的則是建立該例項的建構函式。
如果是一個普通的物件,譬如{name:"zs"}
,在呼叫該方法的時候 [程式碼為:({name:"zs"}).toString()
]得到的結果為[object object]
, 但因為原型鏈方法覆蓋的問題,陣列或其它型別的資料則無法直接呼叫該方法。對於除普通物件外的其它物件型別的資料而言,它們需要通過 call 或 apply 繫結 this 的方式才能呼叫該方法。
console.log(({}).toString()) /* [object Object] */
console.log(Object.prototype.toString.call({})) /* [object Object] */
console.log(Object.prototype.toString.call([])) /* [object Array] */
console.log(Object.prototype.toString.call(new Function)) /* [object Function]*/
console.log(Object.prototype.toString.call(new RegExp)) /* [object RegExp] */
console.log(Object.prototype.toString.call(new Error)) /* [object Error] */
console.log(Object.prototype.toString.call(new Set)) /* [object Set] */
console.log(Object.prototype.toString.call(new Map)) /* [object Map] */
一般而言Object.prototype.toString
方法很好用,But 它也不是萬能的,譬如它無法處理自定義型別的型別檢查( 包括自定義建構函式 和 Class 等)。
function Person() {};
let p = new Person;
class Animal {};
let a = new Animal;
console.log(Object.prototype.toString.call(p)) /* [object Object] */
console.log(Object.prototype.toString.call(a)) /* [object Object] */
對於自定義型別的資料,我們需要通過 instanceof 或者是 constructor 來進行檢查。
instanceof 關鍵字 && constructor 構造器屬性JavaScript 語言中的 instanceof
關鍵字用於檢查某個物件是否是指定建構函式建立的例項物件,在檢查的時候會檢查整條原型鏈。如果準確點說,那麼instanceof
實際上檢查的是某個物件( 左值 )是否在指定建構函式( 右值 )的原型鏈上面,如果在那麼就返回 true ,否則的話就返回 false。
console.log(p instanceof Person) /* true */
console.log(a instanceof Person) /* false */
console.log(a instanceof Animal) /* true */
console.log(a instanceof Function, a instanceof Object) /* false true */
console.log(a.constructor == Person); /* false */
console.log(a.constructor == Animal); /* true */
console.log(a.constructor == Object); /* false */
console.log(p.constructor == Person); /* true */
console.log(({}).constructor == Object) /* true */
console.log(([]).constructor == Array) /* true */
這裡試著給出instanceof
關鍵字的實現程式碼,其實就是個死迴圈和迴圈內原型查詢而已。
/* instanceof 實現原理 */
function mockInstanceof(instance,constructor){
let B = constructor.prototype;
let A = instance.__proto__;
while(true)
{
/* Object.prototype.__proto__ -> null */
if (A == null){
return false;
}
if (A === B){
return true;
}
A = A.__proto__;
}
}
/* 測試資料 */
function Person() { };
function Boy() { };
let p = new Person;
let b = new Boy;
console.log(mockInstanceof(p, Person)) /* true */
console.log(mockInstanceof(p, Object)) /* true */
console.log(mockInstanceof(b, Boy)) /* true */
console.log(mockInstanceof(b, Person)) /* false */