JavaScript 在 运算 或 比较 之前, 会自动进行隐式类型转换. 下面我们来仔细讲一讲 + - * / == 运算符经历了哪些过程.

类型转换

ECMAScript 运行时系统会在需要时从事自动类型转换。为了阐明某些结构的语义,定义一集转换运算符是很有用的。这些运算符不是语言的一部分;在这里定义它们是为了协助语言语义的规范。

  • ToPrimitive
  • ToNumber
  • ToString
  • ToBoolean
  • ToInteger
  • ToInt32:(32 位有符号整数)
  • ToUint32:(32 位无符号整数)
  • ToUint16:(16 位无符号整数)
  • ToObject

下面详细讲讲前三种

ToPrimitive

转为原始类型.

ToPrimitive(input, PreferredType)
输入类型 结果
Undefined 结果等于输入的参数(不转换)。
Null 结果等于输入的参数(不转换)。
Boolean 结果等于输入的参数(不转换)。
Number 结果等于输入的参数(不转换)。
String 结果等于输入的参数(不转换)。
Object 返回该对象的默认值。
对象的默认值由把 PreferredType 传入作为hint参数调用对象的内部方法[[DefaultValue]]得到

对象内部方法 [[DefaultValue]] (hint)

当用 String hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:

  1. str = O.toString();
  2. 如果str为原始值,返回str;
  3. val = O.valueOf();
  4. 如果val为原始值,返回val;
  5. 抛出一个 TypeError 异常。

当用 Number hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:

  1. val = O.valueOf();
  2. 如果val为原始值,返回val;
  3. str = O.toString();
  4. 如果str为原始值,返回str;
  5. 抛出一个 TypeError 异常。

当不用 hint 调用 O 的 [[DefaultValue]] 内部方法时, 如果 O 为Date, 则hint=String, 除此之外, hit=Number。

例子:

ToPrimitive({})
解析:
数据类型为 Object, 调用[[DefaultValue]]
没有用 hint 调用, 则 hint 为 Number
val = O.valueOf();
val 是 {}, 不是原始值
str = O.toString();
str 是 '[object Object]', 是原始值, 返回'[object Object]'
结果: '[object Object]'

ToNumber

转为数字类型.(是 Number(value) 的实现)

Input Type Result
Undefined NaN
Null +0
Boolean true: 1, false: +0
Number 结果等于输入的参数(不转换)。
String 将字符串转换为数字。
Object Apply the following steps:
1. Call ToPrimitive(input argument, hint Number).
2. Call ToNumber(Result(1)).
3. Return Result(2).

ToString

转为字符串类型.(是 String(value) 的实现)

输入类型 结果
Undefined "undefined"
Null "null"
Boolean 如果参数是 true,那么结果为 "true"。
如果参数是 false,那么结果为 "false"。
Number 将数字转换为字符串。
String 结果等于输入的参数(不转换)。
Object Apply the following steps:
1. Call ToPrimitive(input argument, hint String).
2. Call ToString(Result(1)).
3. Return Result(2).

例子:

var obj = {
valueOf: function () {
return 1;
},
toString: function () {
return 2;
}
} Number(obj)
解析:
obj 类型 Object, 调用 ToPrimitive(obj, Number)
用 Number hint 调用 obj 的 [[DefaultValue]] 内部方法
调用 obj 的 valueOf 方法, 结果为 1
返回 ToNumber(1)
结果: 1 String(obj)
解析:
obj 类型 Object, 调用 ToPrimitive(obj, String)
用 String hint 调用 obj 的 [[DefaultValue]] 内部方法
调用 obj 的 toString 方法, 结果为 2
返回 ToString(2)
结果: '2'

类型转换的实际运用

加号运算符:+

lval + rval 运算流程如下:

  1. 令 lprim 为 ToPrimitive(lval).
  2. 令 rprim 为 ToPrimitive(rval).
  3. 如果 Type(lprim) 为 String 或者 Type(rprim) 为 String,则: 返回由 ToString(lprim) 和 ToString(rprim) 连接而成的字符串.
  4. 返回将加法运算作用于 ToNumber(lprim) 和 ToNumber(rprim) 的结果.

例子:

([] + {})
解析:
1. lprim = ToPrimitive([]); // ''
2. rprim = ToPrimitive({}); // '[object Object]'
3. lprim 和 rprim 都为字符串, 返回 ToString('') + ToString('[object Object]') // '[object Object]'
结果: '[object Object]' (undefined + {})
解析:
1. lprim = ToPrimitive([]); // undefined;
2. rprim = ToPrimitive({}); // '[object Object]';
3. Type(rprim) 为 String, 返回 ToString(undefined) + ToString('[object Object]') // 'undefined[object Object]'
结果: 'undefined[object Object]' (undefined + 1)
解析:
1. lprim = ToPrimitive([]); // undefined;
2. rprim = ToPrimitive(1); // 1;
3. Type(lprim) Type(rprim) 都不是 String;
4. 返回 ToNumber(undefined) + ToNumber(1) // NaN
结果: NaN

其他运算符:- * /

lval 和 rval 的 - * / 运算符流程如下:

  1. 令 lnum 为 ToNumber(lval).
  2. 令 rnum 为 ToNumber(rval).
  3. 返回 ToNumber(lprim) 和 ToNumber(rprim) 运算的结果.

非严格相等:==

被比较值 B
Undefined Null Number String Boolean Object
被比较值 A Undefined true true false false false IsFalsy(B)
Null true true false false false IsFalsy(B)
Number false false A === B A === ToNumber(B) A=== ToNumber(B) A== ToPrimitive(B)
String false false ToNumber(A) === B A === B ToNumber(A) === ToNumber(B) ToPrimitive(B) == A
Boolean false false ToNumber(A) === B ToNumber(A) === ToNumber(B) A === B ToNumber(A) == ToPrimitive(B)
Object false false ToPrimitive(A) == B ToPrimitive(A) == B ToPrimitive(A) == ToNumber(B)

A === B

例子:

[] == {}
-> this == this
-> false [] == 0
-> ToPrimitive([]) == 0
-> '' == 0
-> ToNumber('') == 0
-> 0 == 0
-> true [0] == 0
-> ToPrimitive([0]) == 0
-> '0' == 0
-> ToNumber('0') == 0
-> 0 == 0
-> true [11] == 11
-> true ['0'] == false
-> ToPrimitive(['0']) == ToNumber(false)
-> '0' == 0
-> 0 == 0
-> true ({} == '[object Object]')
-> ToPrimitive({}) == '[object Object]'
-> '[object Object]' == '[object Object]'
-> true

参考

JavaScript隐式类型转换(详解 +,-,*,/,==)的更多相关文章

  1. javascript隐式转换详解

    Javascript是web前端开发的必学技术,今天和大家分享的就是javascript的基础知识隐式转换,希望可以帮助大家更好的学习. 转换成布尔类型假 undefined->falSe nu ...

  2. Scala进阶之路-Scala高级语法之隐式(implicit)详解

    Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...

  3. JavaScript 隐式类型转换

    JavaScript 隐式类型转换 原文:https://blog.csdn.net/itcast_cn/article/details/82887895 · 1.1 隐式转换介绍 · 1.2 隐式转 ...

  4. 有趣的JavaScript隐式类型转换

    JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加.之所以不同的数据类型之间可以做运算,是因为 ...

  5. 四种JavaScript隐式类型转换的总结

    一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被 ...

  6. 对存在JavaScript隐式类型转换的四种情况的总结

    一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被 ...

  7. JavaScript 隐式类型转换之:加号+

    加号+,有些情况下,它是算术加号,有些情况下,是字符串连接符号 如果字符串和数字相加,JavaScript会自动把数字转换成字符,不管数字在前还是字符串在前 "2" + 3; // ...

  8. 「译」JavaScript 的怪癖 1:隐式类型转换

    原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...

  9. JavaScript学习总结(二、隐式类型转换、eval())

    一.(避免)隐式类型转换 console.log(false == 0);   //logs true; console.log(false === 0);   //logs false; conso ...

随机推荐

  1. scarky test

  2. git push 时不用每次都输入密码的方法

    在本地克隆下来的git仓库中找到 .git 目录 (.git 目录是隐藏文件夹 在组织->文件夹和搜索选项-> 查看选项卡 -> 隐藏文件和文件夹 -> 显示隐藏的文件.文件夹 ...

  3. leetcode_315_逆序对问题

    题目描述 本题来自于Leetcode的算法题库第315题,具体题目描述如下: 给定一个nums整数数组 ,按要求返回一个counts新数组 .数组 counts 有该性质: counts[i]的值是 ...

  4. 80 remove duplicates from sorted array 2

    | 分类 leetcode  | Follow up for "Remove Duplicates": What if duplicates are allowed at most ...

  5. 递归加法(day1)

    题目:求1+2+-+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句(A?B:C). 使用函数指针 1 2 3 4 5 6 7 8 9 10 ...

  6. 分析Android中View的工作流程

    在分析View的工作流程时,需要先分析一个很重要的类,MeasureSpec.这个类在View的测量(Measure)过程中会用到. MeasureSpec MeasureSpec是View的静态内部 ...

  7. shell 获取字符创长度&&识别当前使用的shell&&检查是否为超级用户

    1.获得字符串长度 可以使用下面的方法获得变量值得长度: length=${#value} 例如: [root@gameserver1 shell]# var=12345678 [root@games ...

  8. 基于Noisy Channel Model和Viterbi算法的词性标注问题

    给定一个英文语料库,里面有很多句子,已经做好了分词,/前面的是词,后面的表示该词的词性并且每句话由句号分隔,如下图所示 对于一个句子S,句子中每个词语\(w_i\)标注了对应的词性\(z_i\).现在 ...

  9. 国产数据库适配publiccms开源项目

    金仓数据库适配 操作说明: 一.在程序的所有实体层添加schema=”public”(这里的public是根据数据库定义的模式) 二.切换数据库,修改配置文件cms.properties里面的cms. ...

  10. Java大浮点数精度

    BigDecimal 精度问题 BigDecimal舍入模式 ROUND_DOWN 向零舍入. 即1.55 变为 1.5 , -1.55 变为-1.5 ROUND_UP 向远离0的方向舍入 即 1.5 ...