關於Javascript中的valueOf與toString

Clearlove發表於2019-02-17
+{ a: 1, toString: function() { return `10` }, valueOf: function() { return `100` } }

以上引申出物件資料的轉換的問題:
所有物件繼承了兩個轉換方法:

  1. toString(): 它的作用是返回一個反映這個物件的字串
  2. valueOf():它的作用是返回它相應的原始值

toString()

toString()函式的作用是返回object的字串表示。
JavaScript中object預設的toString()方法返回字串”[object Object]“。定義類時可以實現新的toString()方法,從而返回更加具有可讀性的結果。
JavaScript對於陣列物件、函式物件、正規表示式物件以及Date日期物件均定義了更加具有可讀性的toString()方法

  • ArraytoString()方法將返回以逗號分隔的陣列成員。
var arr = [1, 2, 3]
arr.toString() // "1,2,3"
  • FunctiontoString()方法將返回函式的文字定義。
var fun = function() { return `fun` }
fun.toString() // "function() { return `fun` }" 
  • RegExptoString()方法與FunctiontoString()方法類似,將返回正規表示式的文字定義。
var reg = /d+/g
reg.toString() // "/d+/g"
  • DatetoString()方法將返回一個具有可讀性的日期時間字串。
var date = new Date()
date.toString() // "Tue Feb 12 2019 14:04:36 GMT+0800 (中國標準時間)"
  • 如果Boolean值是true,則返回 “true”。否則,返回 “false”。
var boolean = true
boolean.toString() // "true"

valueOf()

valueOf()函式的作用是返回該object自身。
toString()一樣,定義類時可以實現新的valueOf()方法,從而返回需要的結果。
JavaScript對於Date物件定義了更加具有可讀性的valueOf()方法:

  • DatevalueOf()方法將返回一個時間戳數值,該數值為Date物件與1970年1月1日零時的時間差(以毫秒為單位)
var date = new Date()
date.valueOf() // 1549951476233
  • 其他一律返回物件本身。

示例

var colors = ["red", "blue", "green"] // 建立一個包含3 個字串的陣列 
alert(colors.toString()) // red,blue,green 
alert(colors.valueOf()) // red,blue,green 
alert(colors) // red,blue,green

三個輸出全部一樣,那麼toString()和valueOf()區別到底是什麼?看下一個我寫的例子:

var arr = [1,2,3]
alert(Array.isArray(arr.valueOf())) // true
alert(Array.isArray(arr.toString())) // false

結果是第一個是true而第二個是false,為什麼呢,其實valueOf()呼叫完以後還是返回一個陣列。這個陣列被alert的時候會呼叫toString()函式,所以不是valueOf()toString()函式相同,而是間接的呼叫了toString()函式!
進一步測試下:

var arr = [1,2,3] 
arr.toString = function () { 
  alert("呼叫了toString函式");
} 
alert(arr.valueOf()) // "呼叫了toString函式"

結果就是我們會看到“呼叫了`toString函式”。
驗證如下程式碼:

var test = { 
  value: 10, 
  toString: function() { 
    console.log(`toString`)
    return this.value
  }, 
  valueOf: function() { 
    console.log(`valueOf`)
    return this.value
  } 
} 
alert(test) // 10 toString 
alert(+test) // 10 valueOf 
alert(`` + test) // 10 valueOf 
alert(String(test)) // 10 toString 
alert(Number(test)) // 10 valueOf 
alert(test == `10`) // true valueOf 
alert(test === `10`) // false

valueOf的意思是返回最適合該物件型別的原始值,而toString則是將在該物件型別的原始值以字串形式返回。

示例1

alert(test) // 10 toString 

這裡我們的alert函式需要是的字串,所以獲取的是字串,而不是原始值,故而呼叫了toString

示例2

alert(+test) // 10 valueOf

同理,alert要的是字串不是原始值,其實是(+test)的結果呼叫了toString,而+test被呼叫了valueOf
為了驗證我們這樣寫:

var test = { 
  value: 1, 
  valueOf: function () { 
    alert("呼叫了test的valueOf函式")
    return this.value 
  }, 
  toString: function () { 
    alert("呼叫了test的toString函式") 
    return this.value 
  } 
}; 
var test2 = { 
  value: +test, 
  valueOf: function () { 
    alert("呼叫了test2的valueOf函式") 
    return this.value;
  }, 
  toString: function () { 
    alert("呼叫了test2的toString函式")
    return this.value 
  } 
}; 
alert(test2)
// 呼叫了test的valueOf函式
// 呼叫了test2的toString函式
// 1

其中讓test2 = +test,那麼即可知道結果,果然如此,呼叫了testvalueOftest2toString

示例3

alert(`` + test) // 10 valueOf 

同理,我們可以把上一段寫的程式裡面的test2: + test改成test2:`` + test

示例4

alert(String(test)) // 10 toString 

String這個強制轉換其實在其內部是呼叫了傳入引數的toString函式

示例5

alert(Number(test)) // 10 valueOf

示例6

alert(test == `10`) // true valueOf

這個裡面的判等的順序是,獲取原始值,然後判斷兩邊的原始值是否相等,所以呼叫valueOf

示例7

alert(test === `10`) // false

===操作符不進行隱式轉換,判全等的第一個步驟是判斷型別,因為型別都不一樣了,所以後面什麼都不會呼叫

總結

valueOf偏向於運算,toString偏向於顯示

  • 在進行強轉字串型別時將優先呼叫toString方法,強轉為數字時優先呼叫valueOf
  • 在有運算操作符的情況下,valueOf的優先順序高於toString

下面給大家簡單說下valueoftostring的區別:

  • valueOf():返回最適合該物件型別的原始值
  • toString(): 將該物件的原始值以字串形式返回

這兩個方法一般是交由JS去隱式呼叫,以滿足不同的運算情況。

  • 在數值運算裡,會優先呼叫valueOf(),如a + b
  • 在字串運算裡,會優先呼叫toString(),如alert(c)

相關文章