在JavaScript中,想要判斷某個對象值屬於哪一種內置類型,最靠譜的作法就是經過Object.prototype.toString方法.瀏覽器
<一>, ECMAScript 3 函數
1. 在ES3中,Object.prototype.toString方法的規範以下:工具
15.2.4.2 Object.prototype.toString()
在toString方法被調用時,會執行下面的操做步驟:測試
1. 獲取this對象的[[Class]]屬性的值.this
2. 計算出三個字符串"[object ", 第一步的操做結果Result(1), 以及 "]"鏈接後的新字符串.spa
3. 返回第二步的操做結果Result(2).prototype
[[Class]]是一個內部屬性,全部的對象(原生對象和宿主對象)都擁有該屬性.在規範中,[[Class]]是這麼定義的code
備註: 而後給了一段解釋對象
全部內置對象的[[Class]]屬性的值是由本規範定義的.全部宿主對象的[[Class]]屬性的值能夠是任意值,甚至能夠是內置對象使用過的[[Class]]屬性的值.[[Class]]屬性的值能夠用來判斷一個原生對象屬於哪一種內置類型.須要注意的是,除了經過Object.prototype.toString方法以外,本規範沒有提供任何其餘方式來讓程序訪問該屬性的值(查看 15.2.4.2).blog
也就是說,把Object.prototype.toString方法返回的字符串,去掉前面固定的"[object "和後面固定的"]",就是內部屬性[[class]]的值,也就達到了判斷對象類型的目的.jQuery中的工具方法$.type(),就是幹這個的.
在ES3中,規範文檔並無總結出[[class]]內部屬性一共有幾種,不過咱們能夠本身統計一下,原生對象的[[class]]內部屬性的值一共有10種.分別是:"Array", "Boolean", "Date", "Error", "Function", "Math", "Number", "Object", "RegExp", "String".
<二>, ECMAScript 5
在ES5.1中,除了規範寫的更詳細一些之外,Object.prototype.toString方法和[[class]]內部屬性的定義上也有一些變化,Object.prototype.toString方法的規範以下:
在toString方法被調用時,會執行下面的操做步驟:
若是this的值爲undefined,則返回"[object Undefined]".
若是this的值爲null,則返回"[object Null]".
讓O成爲調用ToObject(this)的結果.
讓class成爲O的內部屬性[[Class]]的值.
返回三個字符串"[object ", class, 以及 "]"鏈接後的新字符串.
能夠看出,比ES3多了1,2,3步.第1,2步屬於新規則,比較特殊,由於"Undefined"和"Null"並不屬於[[class]]屬性的值,須要注意的是,這裏和嚴格模式無關(大部分函數在嚴格模式下,this的值纔會保持undefined或null,非嚴格模式下會自動成爲全局對象).第3步並不算是新規則,由於在ES3的引擎中,也都會在這一步將三種原始值類型轉換成對應的包裝對象,只是規範中沒寫出來.ES5中,[[Class]]屬性的解釋更加詳細:
全部內置對象的[[Class]]屬性的值是由本規範定義的.全部宿主對象的[[Class]]屬性的值能夠是除了"Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String"以外的的任何字符串.[[Class]]內部屬性是引擎內部用來判斷一個對象屬於哪一種類型的值的.須要注意的是,除了經過Object.prototype.toString方法以外,本規範沒有提供任何其餘方式來讓程序訪問該屬性的值(查看 15.2.4.2).
和ES3對比一下,第一個差異就是[[class]]內部屬性的值多了兩種,成了12種,一種是arguments對象的[[class]]成了"Arguments",而不是之前的"Object",還有就是多個了全局對象JSON,它的[[class]]值爲"JSON".第二個差異就是,宿主對象的[[class]]內部屬性的值,不能和這12種值衝突,不過在支持ES3的瀏覽器中,貌似也沒有發現哪些宿主對象故意使用那10個值.
<三>, ECMAScript 5
ES6中 @@toStringTag很容易改變Object.prototype.toString返回值
let obj = {} Object.defineProperty(obj, Symbol.toStringTag, { get: function() { return "newClass" } }) console.log(Object.prototype.toString.call(obj)) // "[object newClass]"
<四>, 總結
若是咱們要判斷一個某個對象的內置類型,能夠用以下函數
function getClass (a) { const str = Object.prototype.toString.call(a); return /^\[object (.*)\]$/.exec(str)[1].toLocaleUpperCase();
}
測試以下
function foo() { console.log(getClass(arguments)); // ARGUMENTS } foo(); function* nav() { console.log(getClass(arguments)); // ARGUMENTS yield 1; yield 2; } let its = nav(); its.next(); console.log(getClass({})); // OBJECT console.log(getClass([])); // ARRAY console.log(getClass(1234)); // NUMBER console.log(getClass("wuhan")); // STRING console.log(getClass(/^[a-z]+/gi)); // REGEXP console.log(getClass(true)); // BOOLEAN console.log(getClass(new Date())); // DATE console.log(getClass(new Error())); // ERROR console.log(getClass(new Function())); // FUNCTION console.log(getClass(Math)); // MATH console.log(getClass(null)); // NULL console.log(getClass(undefined)); // UNDEFINED