探究JavaScript中的valueOf和toString

JS 中的類型

JS中的類型分爲兩大類: primitiveobject

primitive: null, undefined, Number, String, Boolean, Symbol。
object:不是primitive類型的值,都是object類型。

JS是非嚴格類型的語言

在JS中存在大量的數據隱式轉換,例如 1 + 'a'。對於primitive類型,在不同類型之間有明確的轉換規則:

Number

Number(null) // 0
Number(undefined) // NaN
Number(false) // 0
Number(true) // 1
Number('123') // 123
Number('123a') // NaN
Number('') // 0
Number(Symbol('1')) // TypeError

String

非常直接,將字面量形式直接轉換成字符串形式的字面量

String(null) // 'null'
String(undefined) // 'undefined'
String(NaN) // 'NaN'
String(1) // '1'
String(Symbol('a')) // 'Symbol(a)'

Boolean

Boolean(null) // false
Boolean(undefined) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
/* 其餘情況均爲true */
Boolean('a') // true
Boolean(Symbol('foo')) // true

如果是類型轉換涉及到object類型呢

primitive轉成object

將primitive類型轉成object類型都有對應的構造函數。

Number(1)
String('foo')
Boolean(true)

將object轉換成primitive

在ECMAScript文檔,爲object定義了一個內部方法toPrimitive。它類似於下面的形式

toPrimitive(target, PreferredType?)

target表示需要轉換的對象,PreferredType參數可選,標明想要轉成的類型,string 或 number。
轉換步驟:

  1. 如果沒有定義PreferredType, 則默認爲’default’;
  2. 如果存在自定義的toPrimitive方法,就返回執行自定義toPrimitive方法的結果;
  3. 如果PreferredType 的值爲’default’,默認選擇爲number
  4. 返回系統默認toPrimitive方法的執行結果;

如果執行系統默認的toPrimitive方法,
在輸入對象是object,且 PreferredType的值爲’string’,則優先執行toString方法,沒有則執行valueOf方法。
如果PreferredType的值爲’number’,則優先執行valueOf方法,沒有valueOf方法則執行toString方法。

js中的操作符大部分都是針對primitive類型設計的,如果用這些操作符對object類型進行處理運算,會將object類型先轉成primitive類型的值,然後在進行運算操作。

+[12] // 12
+({}) // NaN
[]==0 // true
{}==0 // false

上述情況走的都是對象自身默認的toPrimitive方法且未指定PreferredType值。
還有一種情況是我們自定義對象的valueOf和toString方法。

var o = {
    value:1,
    toString:function(){
        console.log('toString');
        return 'one';
    },
    valueOf: function(){
        console.log('valueOf');
        return this.value++;
    }
}

alert(o); // 'one'
console.log(o == 1); // true
console.log(o == 2); // true

對象默認的toString和valueOf方法

這兩個方法都在Object.prototype上面。valueOf默認返回對象自身,如果操作對象是基本類型,則只返回一個基本值。怎麼理解這句話呢?

(1).valueOf() // 1
var n = new Number(1); 
n.name="number";
console.log(n);

var m = n.valueOf();
var o = { name: 'object'};
var p = o.valueOf();
console.log(m);
console.log(p);

toString的返回值就比較

ES6中的Symbol.toPrimitive

var o = {
    value:1,
    [Symbol.toPrimitive]: function(hint){
        console.log('Symbol.toPrimitive');
        if(hint === 'number' || hint === 'default') return this.value+=2;
        return 'toprimitive function';
    },
    toString:function(){
        console.log('toString');
        return 'one';
    },
    valueOf: function(){
        console.log('valueOf');
        return this.value++;
    }
}

alert(o); // 'toprimitive function'
console.log(o == 1); // false
console.log(o == 5); // true

ToPrimitive 定義(https://www.ecma-international.org/ecma-262/6.0/#sec-toprimitive)

Data類型的toPrimitive

toPrimitive中還存在另外一個特殊情況。Date類型的對象在執行toPrimitive方法時,PreferredType的默認值爲’string’,而非’number’。
下面例子中,明顯表明 Date類型在執行 +1操作時,先轉成字符串再進行運算; 而普通對象則是先執行valueOf方法,再進行運算;

var d = new Date;
var o = {
    value: 1,
    valueOf: function(){ return 2;},
    toString: function(){ return 'tostring';}
}
d+1;// "Sun Dec 15 2019 21:56:35 GMT+0800 (中國標準時間)1"
o+1; // 3
d.toString=function(){return 'date toString';}
console.log(d); // "date toString"
d+1;// "date toString1"

Summary

valueOftoString是JS中類型轉換中處理object類型的重要組成。

在未自定義的情況下,這兩個方法都在Object.prototype上。 valueOf通常返回對象本身,而toString會根據對象的internal slot返回數據格式如下[object ${Type}]

發佈了41 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章