视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
理解Javascript中的“+”运算符
2020-11-27 20:23:07 责编:小采
文档

在网上或面试题中经常会看到一些“奇怪”的语句,比如

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

{}+[]
// 0

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

[]+[]
// ""

在Javascript中+运算符是个重载运算符,可用来拼接字符串,以及把两个“数字”相加。至于是哪种情况要看运算符两边参数的类型。
在日常的开发中我们也不会碰到这么麻烦的事,但弄弄清楚总是好的。在规范 中巴拉巴拉地说了一堆,简单来说就是:

1. 对于原生类型,参数中只要有一方是字符串,则按字符串连接处理,否则按数字相加处理,不是数字的会先转成数字再相加。

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

下面是一些示例:

0 + '1' // '01'
null + 1 // 1
true + 1 // 2
false + 1 // 0
undefined + 2 // NaN, 因为undefined转成Number是NaN

2. 对于引用类型,则需要先转换成原生类型,再按以上规则相加。如何转换在规范中有详细的说明,但规范看起来是有点费劲。 简单来说就是:默认情况下都转化成字符串,要搞特殊的话,请重写valueOf()方法。

来个例子:

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不支持真正的操作符重载,即不能相加得到自定义类型的对象, 所以以上示例在实践代码中非常少用。

不过目前的知识足够回答原先的问题了。但是慢着,{}+[] 为什么和 []+{}不一样? 这其实是个语法问题。前者相当于:

{}
+[]

其实是两个句子, [] 转换成数字是 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();
}

详细的请参考规范

在网上或面试题中经常会看到一些“奇怪”的语句,比如

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

{}+[]
// 0

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

[]+[]
// ""

在Javascript中+运算符是个重载运算符,可用来拼接字符串,以及把两个“数字”相加。至于是哪种情况要看运算符两边参数的类型。
在日常的开发中我们也不会碰到这么麻烦的事,但弄弄清楚总是好的。在规范 中巴拉巴拉地说了一堆,简单来说就是:

1. 对于原生类型,参数中只要有一方是字符串,则按字符串连接处理,否则按数字相加处理,不是数字的会先转成数字再相加。

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

下面是一些示例:

0 + '1' // '01'
null + 1 // 1
true + 1 // 2
false + 1 // 0
undefined + 2 // NaN, 因为undefined转成Number是NaN

2. 对于引用类型,则需要先转换成原生类型,再按以上规则相加。如何转换在规范中有详细的说明,但规范看起来是有点费劲。 简单来说就是:默认情况下都转化成字符串,要搞特殊的话,请重写valueOf()方法。

来个例子:

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不支持真正的操作符重载,即不能相加得到自定义类型的对象, 所以以上示例在实践代码中非常少用。

不过目前的知识足够回答原先的问题了。但是慢着,{}+[] 为什么和 []+{}不一样? 这其实是个语法问题。前者相当于:

{}
+[]

其实是两个句子, [] 转换成数字是 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();
}

下载本文
显示全文
专题