官术网_书友最值得收藏!

1.5 toString()函數與valueOf()函數

在1.4.1小節關于等于運算符的內容中,如果比較的內容包含對象類型數據,則會涉及隱式轉換,那么就會調用toString()函數和valueOf()函數。本節會詳細講解toString()函數與valueOf()函數,并通過實例來看看它們的使用場景。

在JavaScript中,toString()函數與valueOf()函數解決的是值的顯示和運算的問題,所有引用類型都擁有這兩個函數。

1. toString()函數

toString()函數的作用是把一個邏輯值轉換為字符串,并返回結果。Object類型數據的toString()函數默認的返回結果是"[object Object]",當我們自定義新的類時,可以重寫toString()函數,返回可讀性更高的結果。

在JavaScript中,Array,Function,Date等類型都實現了自定義的toString()函數。

· Array的toString()函數返回值為以逗號分隔構成的數組成員字符串,例如[1, 2,3].toString()結果為字符串'1,2,3'。

· Function的toString()函數返回值為函數的文本定義,例如(function(x){return x *2;}).toString()的結果為字符串"function(x){return x * 2;}"。

· Date的toString()函數返回值為具有可讀性的時間字符串,例如,new Date().toString()的結果為字符串"Sun Nov 25 2018 15:00:16 GMT+0800 (中國標準時間)"。

2. valueOf()函數

valueOf()函數的作用是返回最適合引用類型的原始值,如果沒有原始值,則會返回引用類型自身。Object類型數據的valueOf()函數默認的返回結果是"{}",即一個空的對象字面量。

對于Array、Function、Date等類型,valueOf()函數的返回值是什么呢?

· Array的valueOf()函數返回的是數組本身,例如[1, 2, 3].valueOf()返回的結果為“[1,2,3]”。

· function的valueOf()函數返回的是函數本身,例如(function(x){return x * 2;}).valueOf()返回的結果為函數本身“function(x){return x * 2;}”。

· Date的valueOf()函數返回的是指定日期的時間戳,例如new Date().valueOf()返回的結果為“1543130166771”。

如果一個引用類型的值既存在toString()函數又存在valueOf()函數,那么在做隱式轉換時,會調用哪個函數呢?

這里我們可以概括成兩種場景,分別是引用類型轉換為String類型,以及引用類型轉換為Number類型。

1. 引用類型轉換為String類型

一個引用類型的數據在轉換為String類型時,一般是用于數據展示,轉換時遵循以下規則。

· 如果對象具有toString()函數,則會優先調用toString()函數。如果它返回的是一個原始值,則會直接將這個原始值轉換為字符串表示,并返回該字符串。

· 如果對象沒有toString()函數,或者toString()函數返回的不是一個原始值,則會再去調用valueOf()函數,如果valueOf()函數返回的結果是一個原始值,則會將這個結果轉換為字符串表示,并返回該字符串。

· 如果通過toString()函數或者valueOf()函數都無法獲得一個原始值,則會直接拋出類型轉換異常。

我們通過以下代碼進行測試。


var arr = [];

arr.toString = function () {
     console.log('執行了toString()函數');
     return [];
};

arr.valueOf = function () {
     console.log('執行了valueOf()函數');
     return [];
};

console.log(String(arr));

上面代碼執行后的結果如下所示。


執行了toString()函數
執行了valueOf()函數
TypeError: Cannot convert Object to primitive value

執行String(arr)代碼時,需要將arr轉換為字符串,則會優先執行toString()函數,但是其返回值為空數組[],并不能轉換為原生數據;然后調用valueOf()函數,其返回值同樣為空數組[];那么在調用完toString()函數和valueOf()函數后,均無法獲取到原生數據類型表示,則拋出異常TypeError,表示無法將對象類型轉換為原生數據類型。

2. 引用類型轉換為Number類型

一個引用類型的數據在轉換為Number類型時,一般是用于數據運算,轉換時遵循以下規則。

· 如果對象具有valueOf()函數,則會優先調用valueOf()函數,如果valueOf()函數返回一個原始值,則會直接將這個原始值轉換為數字表示,并返回該數字。

· 如果對象沒有valueOf()函數,或者valueOf()函數返回的不是原生數據類型,則會再去調用toString()函數,如果toString()函數返回的結果是一個原始值,則會將這個結果轉換為數字表示,并返回該數字。

· 如果通過toString()函數或者valueOf()函數都無法獲得一個原始值,則會直接拋出類型轉換異常。

我們通過以下代碼進行測試。


var arr = [];

arr.toString = function () {
   console.log('執行了toString()函數');
   return [];
};

arr.valueOf = function () {
   console.log('執行了valueOf()函數');
   return [];
};

console.log(Number(arr));

上面代碼執行后的結果如下所示。


執行了valueOf()函數
執行了toString()函數
TypeError: Cannot convert Object to primitive value

執行Number(arr)代碼時,需要將arr轉換為數字,則會優先執行valueOf()函數,但是其返回值為空數組[],并不能轉換為原生數據;然后調用toString()函數,其返回值同樣為空數組[];那么在調用完valueOf()函數和toString()函數后,均無法獲取到原生數據表示,則拋出異常TypeError,表示無法將對象類型轉換為原生數據類型。

事實上,對除了Date類型以外的引用類型數據轉換為原生數據類型時,如果是用于數據運算,則會優先調用valueOf()函數,在valueOf()函數無法滿足條件時,則會繼續調用toString()函數,如果toString()函數也無法滿足條件,則會拋出類型轉換異常。

如果是用于數據展示,則會優先調用toString()函數,在toString()函數無法滿足條件時,則會繼續調用valueOf()函數,如果valueOf()函數也無法滿足條件,則會拋出類型轉換異常。

了解了valueOf()函數和toString()函數的關系后,我們再用下面兩組代碼深入拓展一下其他相關知識。

拓展1

看看下面3行代碼,它們的結果有什么不同。


[] == 0; // true
[1] == 1; // true
[2] == 2; // true

在第一行中,空數組可以轉換為數字0;在第二行和第三行中,只有一個數字元素的數組可以轉換為該數字。這是為什么呢?

因為數組繼承了Object類型默認的valueOf()函數,這個函數返回的是數組自身,而不是原生數據類型,所以會繼續調用toString()函數。數組調用toString()函數時會返回數組元素以逗號作為分隔符構成的字符串,那么空數組就轉換為空字符串,而空字符串與數字0在非嚴格相等的情況下是相等的,即'' == 0,返回“true”。

同樣,只包含一個數字的數組[1],轉換后為字符串"1",后判斷"1" == 1,返回“true”。

拓展2

以下是另外一組Object類型的數據,請觀察結果有什么不同。


var obj = {
     i: 10,
     toString: function () {
         console.log('toString');
         return this.i;
     },
     valueOf: function () {
         console.log('valueOf');
         return this.i;
     }
};

+obj;  // valueOf
'' + obj;  // valueOf
String(obj);  // toString
Number(obj);  // valueOf
obj == '10';  // valueOf,true
obj === '10'; // false

第一行執行代碼為+obj,將對象obj轉換為原始值,用于數據運算,優先調用valueOf()函數,獲得原始值,結果為數字“10”。

第二行執行代碼為'' + obj,將對象obj轉換為原始值,用于數據運算,優先調用valueOf()函數,獲取原始值,并與字符串進行拼接,結果為字符串"10"。

第三行執行代碼為String(obj),在String()函數中,用于數據展示,優先調用toString()函數獲取對象的字符串表示,結果為字符串"10"。

第四行執行代碼為Number(obj),將對象obj轉換為數值表示,用于數據運算,優先調用valueOf()函數,結果為數字“10”。

第五行執行代碼為obj == '10',將對象obj轉換為原始值,用于數據運算,優先調用valueOf()函數,即將10與'10'進行比較,兩者是相等的,結果為“true”;

第六行執行代碼為obj === '10',因為兩者數據類型不一致,直接返回“false”,并不會執行toString()函數或者valueOf()函數。

主站蜘蛛池模板: 思茅市| 柏乡县| 蓬溪县| 双桥区| 太保市| 荔波县| 宁海县| 宜宾市| 神木县| 武乡县| 千阳县| 东安县| 通州市| 定远县| 长阳| 和平区| 靖江市| 天津市| 聂拉木县| 班戈县| 永和县| 静海县| 麻城市| 武川县| 潍坊市| 高雄市| 临武县| 肇源县| 阿克陶县| 曲松县| 鹿泉市| 安化县| 吴堡县| 肇州县| 麻城市| 武陟县| 萝北县| 密云县| 阳西县| 西安市| 永宁县|