Javascript中的+運算符

在網上或面試題中常常會看到一些「奇怪」的語句,好比html

{}+{}
// "[object Object][object Object]"

{}+[]
// 0

[]+{}
// "[object Object]"

[]+[]
// ""

在Javascript中+運算符是個重載運算符,可用來拼接字符串,以及把兩個「數字」相加。至因而哪一種狀況要看運算符兩邊參數的類型。
在平常的開發中咱們也不會碰到這麼麻煩的事,但弄弄清楚老是好的。在規範 中巴拉巴拉地說了一堆,簡單來講就是:面試

1. 對於原生類型,參數中只要有一方是字符串,則按字符串鏈接處理,不然按數字相加處理,不是數字的會先轉成數字再相加。this

原生類型有:undefined, null, boolean, number, string。prototype

下面是一些示例:code

0 + '1'     // '01'
null + 1    // 1
true + 1    // 2
false + 1   // 0
undefined + 2   // NaN,  由於undefined轉成Number是NaN

2. 對於引用類型,則須要先轉換成原生類型,再按以上規則相加。如何轉換在規範中有詳細的說明,但規範看起來是有點費勁。 簡單來講就是:默認狀況下都轉化成字符串,要搞特殊的話,請重寫valueOf()方法。 htm

來個例子:對象

function Complex(a, b) {
  this.a = a;
  this.b = b;
}

Complex.prototype.valueOf() {
  return this.a;
}

new Complex(2, 3) + new Complex(4, 5);
// 6

但因爲Js不支持真正的操做符重載,即不能相加獲得自定義類型的對象, 因此以上示例在實踐代碼中很是少用。 ip

不過目前的知識足夠回答原先的問題了。可是慢着,{}+[] 爲何和 []+{}不同? 這實際上是個語法問題。前者至關於:開發

{}
+[]

實際上是兩個句子, [] 轉換成數字是 0。很容易驗證 ({}+[]) === '[object Object]'字符串

+[]  // 0

有人可能要問,那 new Date()valueOf() 不是轉換成數字嗎?爲何相加結果仍是字符串類型呢?

new Date().valueOf();
// 1491904757087

1 + new Date();
// "1Tue Apr 11 2017 18:02:16 GMT+0800 (CST)"

這是Date類作了特殊處理, @@toPrimitive, 默認狀況下對 Date 的相加以字符串方式鏈接,但比較時則會轉換成數字。

new Date() < new Date('2018-01-01')
// true, 如今是2017

將引用類型轉換成原生類型在不少操做符中都有用到,好比 <, >, 因此有必要對其研究一番, 如下js代碼大概描述了其行爲。

/**
 * @param input     即要轉換的對象
 * @preferredType   指望轉換成的類型,能夠是string或number
 */
function ToPrimitive(input, preferredType) {
  if (typeof input !== 'object') {
    return input;   // 原本就是原生類型
  }

  var hint = preferredType || 'default';
  if (typeof input['@@toPrimitive'] === 'function') {   // @@toPrimitive是個內部方法,這裏只是示例說明其工做原理
    return input['@@toPrimitive'](input, hint);   // 這就是爲何Date能特殊處理的緣由
  }

  if (hint === 'string') {
    return input.toString();
  }

  return input.valueOf();
}

詳細的請參考規範

相關文章
相關標籤/搜索