将介绍JavaScript中 '+'加号运算符在一元、二元运算时的表现。

目录

1.一元运算符

2. 二元运算符

1. 一元运算符

语法: + Expression

说明:'+'号运算符作为一元运算符时,Expression将进行ToNumber()操作。

ToNumber( argument )转换方式:

argument类型 返回值
Undefined return NaN
Null return +0
Boolean true return 1; false return 0;
Number return value
String 若字符串为纯数字时返回转换后的数字;非纯数字返回NaN
Symbol 抛出 TypeError 异常
Object

进行以下步骤:

1.先进行ToPrimitive(argument, hint Number)得到rs;
2.然后返回 ToNumber(rs)的结果。

示例:

// Undefined
+ undefined; // => NaN // Null
+ null; // => 0 // Boolean
+ true; // => 1
+ false; // => 0 // String
+ '1'; // => 1
+ '-1'; // => -1
+ 'a1'; // => NaN // Object
+ {}; // => NaN
+ { valueOf: function () { return 0 } }; // => 0

  

2. 二元运算符

语法: AdditiveExpression + MultiplicativeExpression

2.1 解析步骤

首先看下ECMAScript 2015(ES6)关于加法运算符的说明:

AdditiveExpression : AdditiveExpression + MultiplicativeExpression

  1. Let lref be the result of evaluating AdditiveExpression.

  2. Let lval be GetValue(lref).

  3. ReturnIfAbrupt(lval).

  4. Let rref be the result of evaluating MultiplicativeExpression.

  5. Let rval be GetValue(rref).

  6. ReturnIfAbrupt(rval).

  7. Let lprim be ToPrimitive(lval).

  8. ReturnIfAbrupt(lprim).

  9. Let rprim be ToPrimitive(rval).

  10. ReturnIfAbrupt(rprim).

  11. If Type(lprim) is String or Type(rprim) is String, then

    1. Let lstr be ToString(lprim).

    2. ReturnIfAbrupt(lstr).

    3. Let rstr be ToString(rprim).

    4. ReturnIfAbrupt(rstr).

    5. Return the String that is the result of concatenating lstr and rstr.

  12. Let lnum be ToNumber(lprim).

  13. ReturnIfAbrupt(lnum).

  14. Let rnum be ToNumber(rprim).

  15. ReturnIfAbrupt(rnum).

  16. Return the result of applying the addition operation to lnum and rnum. See the Note below 12.7.5.

链接:http://www.ecma-international.org/ecma-262/6.0/#sec-addition-operator-plus

简单概括为下面4个步骤:

1) 值进行GetValue()操作。

2) 值进行ToPrimitive()操作,

3) 若一方为String类型,2个值都进行ToString()转换,最后进行字符串连接操作。

4) 若都不是String类型,2个值都进行ToNumber()转换,最后进行算数加法运算。

2.2 ToPrimitive(value)方法说明

在上面的步骤中,重点说明是其中的ToPrimitive()方法,除了在'+'号运算符用到此方法外,ToNumber()、ToString()等也都用到此方法。

2.2.1 方法签名

语法:ToPrimitive ( input [, PreferredType] )

参数:

①参 input :传入的值。

②参数 PreferredType :可选,需要被转换的类型。'+'加号作为一元运算符时,此值为“number”;而作为二元运算符时,未传递此值,以默认的“default”代替。

2.2.2 解析说明

ToPrimitive()的详细解析过程可以看这里:http://www.ecma-international.org/ecma-262/6.0/#sec-toprimitive

简化为以下步骤:

1) 若input类型为原始值(如:Undefined、Null、Boolean、Number、String、Symbol),直接返回input的本身。

2) 若input类型为object(如:Array、Object、Date),将根据第②个参数 PreferredType 的值进行以下操作:

就像之前讲的,'+'加号作为一元运算符时, 传递参数 PreferredType 的值为“number”;而作为二元运算符时,未传递此值时以默认的“default”代替。

在上面的图中,只看到 PreferredType 的值为“number” 或 “string” 时才进行解析,那么默认的“default”表示什么呢?

重点来了:Date类型内部重写了@@toPrimitive()方法,将“default”设置为“string”,而其他内置的对象都将“default”设置为“number”。

Date.prototype[@@toPrimitive]:http://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@toprimitive

2.3 示例

1) String + String

说明:进行字符串连接操作

'a' + 'b'; // => 'ab'
'1' + '2'; // => '12'

2) Number + Number

说明:进行算数的加法操作

1 + 2; // => 3

3) Number + String or String + Number

说明:Number类型的值先进行ToString()转换,随后再与另一个String类型的值进行拼接操作

1 + '0'; // => '10'
1 + '0a'; // => '10a'
'1' + 2; // => 12

4) Array + String or Array + Number

说明:Array类型进行ToPrimitive()转换时,先执行valueOf(),因其返回一个object类型的值,所以又执行了toString()方法。

var tmpList = ['a', 'b', 'c'];
tmpList.valueOf(); // => ["a", "b", "c"] 输出自身
tmpList.toString(); // a,b,c // 1.Array + String
tmpList + 'd'; // => a,b,cd // 2.重写Array的valueOf()方法,使其返回一个非object
Array.prototype.valueOf = function (e) {
return this.join('-');
}
tmpList + 'd'; // => a-b-cd

  

5) Date + String or Date + Number

说明:上面已经讲过,Date类型重写了ToPrimitive(),所以先调用toString(),若返回值为object,再调用valueOf()。

var dt = new Date();
dt.valueOf(); // => 1503501745901
dt.toString(); // Wed Aug 23 2017 23:22:25 GMT+0800 (中国标准时间) // 1.Date + String : dt直接使用了dt.toString()方法
dt + 'd'; // => Wed Aug 23 2017 23:22:25 GMT+0800 (中国标准时间)d // 2.重写Date的toString()方法,使其返回一个object的值
Date.prototype.toString = function (e) {
return { year: this.getFullYear() };
}
// 略过了 dt.toString(),调用了 dt.valueOf()
dt + 'd'; // => 1503501745901d
End
菜单加载中...

最新文章

  1. position:sticky的兼容性尝试
  2. Python 模块学习:os模块
  3. CSS3常用选择器(三)
  4. IOS Block-Block块的使用与理解
  5. IT笔试题
  6. Ubuntu14.04设置开机root用户登录
  7. python 以标准输出(sys.stdout)为例,看python的标准输入、标准错误输出
  8. AlertDialog基本用法详解
  9. java.lang.NoSuchMethodError: org.springframework.beans.factory.annotation.InjectionMetadata.<init>(L
  10. Intelli idea 常用快捷键汇总
  11. Struts2学习笔记(一)——环境搭建
  12. Tomcat下使用Druid配置JNDI数据源
  13. Java 8新特性探究(一) JEP126特性lambda表达式和默认方法
  14. ElasticSearch(三)不仅仅是查询
  15. Day Two
  16. html+css小总结
  17. sql 关于存储过程的查询
  18. C标准中一些预定义的宏,如__FILE__,__func__等
  19. 约束,索引,rownum&rownum
  20. Mybatis源码分析之结果集处理

热门文章

  1. Javascript 判断变量类型的陷阱 与 正确的处理方式
  2. 防止js全局变量污染方法总结
  3. Ant部署(linux)
  4. jsonp的原理和实现
  5. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)A B题
  6. windows下安装DB2数据库以及使用Aqua Data Studio链接数据库
  7. JavaScript中的函数:闭包,this,高阶函数
  8. 51nod_1298:圆与三角形(计算几何)
  9. (转)maven打包时跳过测试
  10. 从Ubunt的安装到hadoop集群的搭建