談談 Object.prototype.toString

ECMAScript 5

在ECMAScript 5中,Object.prototype.toString()被調用時,會進行如下步驟:

  • 如果 thisundefined ,返回 object Undefined
  • 如果 thisnull , 返回 object Null
  • O 爲以 this 作爲參數調用 ToObject的結果;
  • classO 的內部屬性 [[Class]] 的值;
  • 返回三個字符串 "[object", class, 以及"]" 拼接而成的字符串。

[[Class]]

[[Class]] 是一個內部屬性,值爲一個類型字符串,可以用來判斷值的類型。

有這麼一段詳細的解釋:

本規範的每種內置對象都定義了 [[Class]] 內部屬性的值。宿主對象的 [[Class]] 內部屬性的值可以是除了 “Arguments”, “Array”, “Boolean”, “Date”, “Error”, “Function”, “JSON”, “Math”, “Number”, “Object”, “RegExp”, “String” 的任何字符串。[[Class]] 內部屬性的值用於內部區分對象的種類。注,本規範中除了通過 Object.prototype.toString ( 見 15.2.4.2) 沒有提供任何手段使程序訪問此值。

在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]'

	Object.prototype.toString.call(0)
	// => '[object Number]'

	Object.prototype.toString.call(NaN)
	// => '[object Number]'
	
	Object.prototype.toString.call('')
	// => '[object String]'

因此,可以用下列函數,來獲取任意變量的[[Class]]屬性:

	function getType (val) {
	  const _str = Object.prototype.toString.call(val)
	  return /^\[object (.*)\]$/.exec(_str)[1]
	}

運行:

	getClass(null)
	// => 'Null'
	
	getClass(undefined)
	// => 'Undefined'
	
	getClass(Math)
	// => 'Math'
	
	getClass({})
	// => 'Object'
	
	getClass([])
	// => 'Array'

ECMAScript 6

在ES6,調用 Object.prototype.toString 時,會進行如下步驟:

  • 如果 thisundefined ,返回 '[object Undefined]';
  • 如果 thisnull , 返回 '[object Null]'
  • O 爲以 this 作爲參數調用 ToObject 的結果;
  • isArrayIsArray(O)
  • ReturnIfAbrupt(isArray) (如果 isArray 不是一個正常值,比如拋出一個錯誤,中斷執行);
  • 如果 isArraytrue , 令 builtinTag'Array' ;
  • else ,如果 O is an exotic String object , 令 builtinTag'String'
  • else ,如果 O 含有 [[ParameterMap]] internal slo, , 令 builtinTag 爲 'Arguments'
  • else ,如果 O 含有 [[Call]] internal method , 令 builtinTagFunction
  • else ,如果 O 含有 [[ErrorData]] internal slot , 令 builtinTag 爲Error` ;
  • else ,如果 O 含有 [[BooleanData]] internal slot , 令 builtinTagBoolean
  • else ,如果 O 含有 [[NumberData]] internal slot , 令 builtinTagNumber
  • else ,如果 O 含有 [[DateValue]] internal slot , 令 builtinTag 爲 Date
  • else ,如果 O 含有 [[RegExpMatcher]] internal slot , 令 builtinTagRegExp
  • else , 令 builtinTagObject
  • tagGet(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]"

參考:

  1. http://www.ecma-international.org/ecma-262/5.1
  2. http://www.adobe.com/devnet/archive/html5/articles/categorizing-values-in-javascript.html
  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
  4. http://www.ecma-international.org/ecma-262/6.0/
  5. http://es6.ruanyifeng.com/#docs/symbol
  6. https://tc39.github.io/ecma262/#sec-object.prototype.tostring
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章