從 ES 規範的角度講解 +、Number 類型轉換

分析下面代碼的執行流程。html

var obj = {
  value: 3,
  valueOf() {
    return 4;
  },
  toString() {
    return '5'
  },
}
+obj // 4
''+obj // '4'
`${obj}` // '5'


複製代碼

ToPrimitive 轉換爲原始值

Symbol.toPrimitive

原始值 primitive valueUndefined, Null, Boolean, Number, Symbol, String 之一,原始值是直接在語言實現的最低級別表示的數據。前端

當對象要被轉換爲數字或者字符串時,將會涉及到 ToPrimitive ( input [ , PreferredType ] ) 轉換。程序員

  • PreferredType 表示對象將要轉換的類型
    • PreferredType 未傳遞,則令 hintdefault
    • PreferredType 爲 String,則 hintstring
    • PreferredType 爲 Number,則 hintnumber

Symbol.toPrimitive 屬性(用做函數值)的幫助下,一個對象可被轉換爲原始值。該函數被調用時,會被傳遞一個字符串參數 hint ,表示要轉換到的原始值的預期類型。 hint 參數的取值是 "number"、"string" 和 "default" 中的任意一個。es6

經過Symbol.toPrimitive 咱們能夠自定義在轉換爲目標原始值時的一些行爲和返回值(返回值不能是非原始值,不然報錯),若是沒有這個屬性,則會調用 valueOf 或者 toStringbash

var obj = {
  value: 3,
  valueOf() {
    return 4;
  },
  toString() {
    return '5'
  },
  [Symbol.toPrimitive](hint) {
    console.log('hint', hint)
    return 6
  }
}
複製代碼

image

valueOftoString

若是沒有定義 Symbol.toPrimitive,那麼轉換會經過 valueOftoStirng 處理以後返回。下面看看轉換順序和規則。函數

若是 hint 推斷類型是 default(Date 對象除外) ,則認爲它是 number,如今就只有 numberstring 兩種類型。ui

  • hintstring,即要轉換爲字符串,則先用 toString處理,若是是原始值則返回,不然再用 valueOf 處理,若是返回是原始值則返回,不然會報 TypeError 錯誤;
  • hintnumber,則先用 valueOf 再用 toStringvalueOf 執行能返回原始值則直接返回不會執行 toString,若是 toString 返回的結果不是原始值則會報 TypeError 錯誤;

上面的規則應用於大多數場景。但對 Date 不適用,日期對象沒有 hint,認爲 hintstring 以下面的例子,'' + d,對通常對象,hintdefault,由前面知道 defaultnumber,對日期對象 hintstringthis

看下面三個例子es5

對象默認的 valueOf 返回本身。spa

var obj = {}

obj === obj.valueOf() // true
複製代碼
var obj = {
  value: 3,
  valueOf() {
	console.log('valueof')
    return this;
  },
  toString() {
    return '5'
  },
}

+obj
// valueof 由於要轉換位數字,因此執行了 valueOf,可是返回是對象,因此又執行 toString
// 5
複製代碼
var d = new Date()

+d // 1571718957902 時間戳
''+d // "Tue Oct 22 2019 12:35:57 GMT+0800 (China Standard Time)" 字符串,涉及到先轉換後拼接
`${d}` // "Tue Oct 22 2019 12:35:57 GMT+0800 (China Standard Time)" 字符串
複製代碼

一元 + 運算符

+'5'
複製代碼

規範

ToNumber(GetValue(expr))

歸納來講就是轉換時 hintnumber,對於原始值類型(Undefined, Null, Boolean, Number, Symbol, String),直接使用內部 ToNumber 轉換成數字,下面是轉換規則。對於對象,先使用 ToPrimitive 再使用 ToNumber

image

來幾個例子。

+undefined // NaN
+null  // 0
+true // 1
+false // 0
+'6.11' // 6.11
+'6.1e15' // 6100000000000000
+'6.1e21' // 6.1e+21
+' 6 ' // 6
+' 6 7 8 ' // NaN
+'0xf' // 15
+'f' // NaN

var obj = {
  value: 3,
  valueOf() {
    return 4;
  },
  [Symbol.toPrimitive](hint) {
    console.log('hint', hint)
    return 6
  }
}
+obj
// hint number
// 6

var obj = {
  value: 3,
  valueOf() {
    return 4;
  },
}
+obj
// 4
複製代碼

Number

Number 當作一個函數來使用。

規範

若是提供了 value,返回 ToNumber(value) 計算出的數字值(非 Number 對象),不然返回 +0。

從規範看出,Number+ 運算符少了 GetValueGetValue 有和沒有對原始值是沒有影響的,只對對象有影響。

Number(x)+x 的結果在大多數時候能夠認爲是徹底同樣的,處理字符串時徹底能夠互換。

參考


今天的文章就到這裏,感謝閱讀~

歡迎你們關注個人掘金和公衆號,專一於提高前端程序員的核心競爭力

相關文章
相關標籤/搜索