原文連接個人blog。javascript
前幾日看到一個比較熟悉的面試題,判斷一個變量是否是數組?
如下幾種方法供參考:html
var arr = [1, 2, 3]
Array.isArray(arr)
arr instanceof Array
arr.constructor === Array
Object.prototype.toString.call(arr) === '[object Array]'
...複製代碼
這篇文章主要是談談 Object.prototype.toString
。html5
在ECMAScript 5中,Object.prototype.toString()
被調用時,會進行以下步驟:java
this
是undefined
,返回 [object Undefined]
;this
是null
, 返回 [object Null]
;O
爲以 this
做爲參數調用 ToObject
的結果;class
爲 O
的內部屬性 [[Class]]
的值; "[object", class, 以及"]"
拼接而成的字符串。[[Class]]
是一個內部屬性,值爲一個類型字符串,能夠用來判斷值的類型。git
有這麼一段詳細的解釋:es6
本規範的每種內置對象都定義了 [[Class]] 內部屬性的值。宿主對象的 [[Class]] 內部屬性的值能夠是除了 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String" 的任何字符串。[[Class]] 內部屬性的值用於內部區分對象的種類。注,本規範中除了經過 Object.prototype.toString ( 見 15.2.4.2) 沒有提供任何手段使程序訪問此值。github
在JavaScript代碼裏,惟一能夠訪問該屬性的方法就是經過 Object.prototype.toString
,一般方法以下:面試
Object.prototype.toString.call(value)複製代碼
舉例:算法
> Object.prototype.toString.call(null)
'[object Null]'
> Object.prototype.toString.call(undefined)
'[object Undefined]'
> Object.prototype.toString.call(Math)
'[object Math]'
> Object.prototype.toString.call({})
'[object Object]'
> Object.prototype.toString.call([])
'[object Array]'複製代碼
所以,能夠用下列函數,來獲取任意變量的[[Class]]
屬性:數組
function getClass (a) {
const str = Object.prototype.toString.call(a)
return /^\[object (.*)\]$/.exec(str)[1]
}複製代碼
運行便可得
> getClass(null)
'Null'
> getClass(undefined)
'Undefined'
> getClass(Math)
'Math'
> getClass({})
'Object'
> getClass([])
'Array'複製代碼
在ES6,調用 Object.prototype.toString
時,會進行以下步驟:
this
是 undefined
,返回 '[object Undefined]'
;this
是 null
, 返回 '[object Null]'
;O
爲以 this
做爲參數調用 ToObject
的結果;isArray
爲 IsArray(O)
;ReturnIfAbrupt(isArray)
(若是 isArray
不是一個正常值,好比拋出一個錯誤,中斷執行);isArray
爲 true
, 令 builtinTag
爲 'Array'
;else
,若是 O is an exotic String object
, 令 builtinTag
爲 'String'
;else
,若是 O
含有 [[ParameterMap]] internal slot,
, 令 builtinTag
爲 'Arguments'
; else
,若是 O
含有 [[Call]] internal method
, 令 builtinTag
爲 Function
;else
,若是 O
含有 [[ErrorData]] internal slot
, 令 builtinTag
爲 Error
;else
,若是 O
含有 [[BooleanData]] internal slot
, 令 builtinTag
爲 Boolean
;else
,若是 O
含有 [[NumberData]] internal slot
, 令 builtinTag
爲 Number
;else
,若是 O
含有 [[DateValue]] internal slot
, 令 builtinTag
爲 Date
;else
,若是 O
含有 [[RegExpMatcher]] internal slot
, 令 builtinTag
爲 RegExp
;else
, 令 builtinTag
爲 Object
;tag
爲 Get(O, @@toStringTag)
的返回值( Get(O, @@toStringTag)
方法,既是在 O
是一個對象,而且具備 @@toStringTag
屬性時,返回 O[Symbol.toStringTag]
);ReturnIfAbrupt(tag)
,若是 tag
是正常值,繼續執行下一步;Type(tag)
不是一個字符串,let tag be builtinTag
;"[object", tag, and "]"
拼接而成的一個字符串。在ES6裏,以前的 [[Class]]
再也不使用,取而代之的是一系列的 internal slot
,有一個比較完整的解釋:
Internal slots correspond to internal state that is associated with objects and used by various ECMAScript specification algorithms. Internal slots are not object properties and they are not inherited. Depending upon the specific internal slot specification, such state may consist of values of any ECMAScript language type or of specific ECMAScript specification type values
大概的意思是:Internal slots 對應於與對象相關聯並由各類ECMAScript規範算法使用的內部狀態,它們沒有對象屬性,也不能被繼承,根據具體的 Internal slot 規範,這種狀態能夠由任何ECMAScript語言類型或特定ECMAScript規範類型值的值組成。
此外,經過對 Object.prototype.toString
在ES6的實現步驟分析,咱們其實能夠很容易改變 Object.prototype.toString.call
的結果,像下面同樣:
let obj = {}
Object.defineProperty(obj, Symbol.toStringTag, {
get: function() {
return "newClass"
}
})
console.log(Object.prototype.toString.call(obj)) // "[object newClass]"複製代碼
ES7目前仍是工做草案,到目前爲止,就 Object.prototype.toString
的實現步驟來講, 只是移除了ES6其中的 ReturnIfAbrupt
。
完。