這篇文章帶給大家的內容是關於ECMAScript7規格中ToPrimitive抽像操作的詳細解析(範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
本文將介紹ECMAScript7規格中的ToPrimitive抽像操作。
ECMAScript資料型別細分為兩大類別資料型別,一種是語言類型,一種是規範類型:
語言類型是可以直接被開發人員使用的資料型別;
規範型別代表meta-values(元值),用在演算法中描述ECMAScript語言結構和語言類型的語意。它們主要用於規範的說明,不需要被真正實現。
ECMAScript的語言類型一共有7種:
Undefined
#Null
Boolean,布林類型
##String,字串類型Symbol,符號類型Number,數字類型Object,物件類型原始資料類型是上述Undefined、Null、Boolean、String、Symbol和Number的統稱,也就是非物件資料型態。下文涉及的規範類型只有List,也就是列表,類似數組,用符號« »表示。
input#的資料型別
|
|
---|---|
傳回input自身 | |
傳回input自身 | |
#Boolean | 返回input自身 |
Number | #回傳input自身 |
如果input的資料型別是對象,執行下述步驟:
#1、如果沒有傳入PreferredType參數,讓hint等於"default";
2、如果PreferredType是hint String,讓hint等於"string";
3、如果PreferredType是hint Number,讓hint等於"number";
4、讓exoticToPrim等於GetMethod(input, @@toPrimitive),大概語意就是取得參數input的@@toPrimitive方法;
5、如果exoticToPrim不是Undefined,那麼:
讓result等於Call(exoticToPrim, input, « hint »),大概語意就是執行exoticToPrim(hint);
如果result是原始資料類型,則傳回result;
拋出類型錯誤的例外;
6、如果hint是"default",讓hint等於"number";
7、傳回OrdinaryToPrimitive(input, hint)抽象運算的結果。
O的資料型別是對象,hint的資料型別是字串,而hint的值不是"string",就是"number"。這個抽象運算的步驟如下:
1、如果hint是"string",讓methodNames等於« "toString", "valueOf" »;
2、如果hint是"number",讓methodNames等於« "valueOf", "toString" »;
3、依序迭代列表methodNames,對於每一個迭代值name:
讓method等於Call(method, O),大概語意就是執行method();
如果result的型別不是對象,回傳result;
讓method等於Get(O, name),大概語意就是取得對象O的name值對應的屬性;
如果method可以調用,那麼:
4、拋出類型錯誤的例外。
由上述操作步驟可知:
透過ToPrimitive的步驟6可知,當沒有提供可選參數PreferredType的時候,hint會預設為"number";
#透過ToPrimitive的步驟4可知,可以透過定義@@toPrimitive方法來覆寫預設行為,例如規格中定義的Date日期物件和Symbol符號物件都在原型上定義了@@toPrimitive方法。
可能有人會問,為什麼要講解規範中的抽象方法,抽象方法我又用不到。其實不然,這個方法在很多地方都會用到,但你不知道罷了。下面透過講解幾個實例讓大家加深對它的理解。
'' + [1, 2, 3] // "1,2,3"
根據規格中的加法操作,對於操作x y,會呼叫ToPrimitive(x)和ToPrimitive(y)把x和y轉化為原始資料型別。上面的例子中''本身就是原始資料型別了,所以回傳''自身。 [1, 2, 3]是物件類型,陣列沒有定義@@toPrimitive屬性。因為沒有提供PreferredType,所以在ToPrimitive操作的步驟6中,hint變成"number",所以OrdinaryToPrimitive中的methodNames是« "valueOf", "toString" »。
var a = [1, 2, 3] a.valueOf() // [1, 2, 3],数组a本身 a.toString() // "1,2,3"
因為valueOf回傳的是陣列a本身,還是物件類型,所以會繼續呼叫toString方法,回傳了字串"1,2,3",所以
'' + [1, 2, 3] // => '' + '1,2,3' => '1,2,3'
那麼,如果我們覆寫數組原型上的valueOf方法,使得該方法傳回一個原始資料類型,那麼結果會是什麼呢?
var a = [1, 2, 3] a.valueOf = function () { console.log('trigger valueOf') return 'hello' } '' + a // => '' + 'hello' => 'hello'
覆蓋預設的valueOf之後,呼叫valueOf會傳回原始資料類型。根據OrdinaryToPrimitive的3.2.2,這個時候就直接回傳了,不會再呼叫toString方法。同時在控制台會log出"trigger valueOf",也就是說valueOf確實是呼叫了。
那麼,如果我們覆寫數組預設的toString方法,使得該方法傳回物件類型,那麼結果會是什麼呢?
var a = [1, 2, 3] a.toString = function () { console.log('trigger toString') return this } '' + a // Uncaught TypeError: Cannot convert object to primitive value
因為陣列原型上的valueOf方法傳回物件類型,在上面的例子中,我們把toString覆寫了,使它也傳回物件類型,那麼就會直接走到OrdinaryToPrimitive的第4步,也就是拋出類型錯誤的異常,不能把物件轉化為原始資料類型。
在上面我們提到過可以透過@@toPrimitive方法來自訂ToPrimitive的行為,例如下面的例子:
var a = [1, 2, 3] a[Symbol.toPrimitive] = function () { return 'custom' } '' + a // => '' + 'custom' => 'custom'
相加操作在呼叫ToPrimitive的時候沒有提供PreferredType,接下來講一個會優先使用hint String作為PreferredType的範例:
var a = [1, 2, 3] a.valueOf = function () { console.log('trigger valueOf') return 'hello' } a.valueOf() // "hello" a.toString() // "1,2,3" var obj = {} obj[a] = 'hello' // obj是{1,2,3: "hello"}
在把變數當作鍵值使用的時候,會呼叫ToPrimitive把鍵值轉換為原始資料類型,而PreferredType的值是hint String。透過上面的例子也可以看出來,a.valueOf和a.toString的結果都是字串,但是使用了'1,2,3',也就是使用了a.toString的結果。當然,如果我們重新定義toString方法,並且傳回對象,那麼就會使用valueOf的值了:
var a = [1, 2, 3] a.valueOf = function () { console.log('trigger valueOf') return 'hello' } a.toString = function () { console.log('trigger toString') return this } var obj = {} obj[a] = 'hello' // obj是{hello: "hello"}
並且會在控制台先log出"trigger toString",後log出"trigger valueOf"。當然,如果這兩個都回傳對象,那麼還是會報錯:
var a = [1, 2, 3] // 使用原型链上的valueOf方法 a.toString = function () { console.log('trigger toString') return this } var obj = {} obj[a] = 'hello' // Uncaught TypeError: Cannot convert object to primitive value
Date
在上面讲ToPrimitive的时候,提到Date对象和Symbol对象在原型上定义了@@toPrimitive方法。在ToPrimitive的第6步的操作中,我们可以看到当没有提供PreferredType的时候,优先调用valueOf方法。Date原型上的@@toPrimitive做的事情非常简单:当没有提供PreferredType的时候,优先调用toString方法。所以对于上面的操作,Date对象的行为是不一样的:
var a = [1, 2, 3] a.valueOf = function () { return 'hello' } a.valueOf() // "hello" a.toString() // "1,2,3" '' + a // "hello" var date = new Date() date.valueOf() // 1536416960724 date.toString() // "Sat Sep 08 2018 22:29:20 GMT+0800 (中国标准时间)" '' + date // "Sat Sep 08 2018 22:29:20 GMT+0800 (中国标准时间)"
我们可以看到date的valueOf方法和toString方法都返回原始数据类型,但是优先使用了toString方法。
总结
本文主要讲解了ToPrimitive抽象操作,以及一些相关的例子,希望大家能有所收获。
以上是詳解ECMAScript7規範中ToPrimitive抽像操作的知識(範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!