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();
}

详细的请参考规范

相关文章
相关标签/搜索