JavaScript隐式类型转换(详解 +,-,*,/,==)
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]] 内部方法,采用以下步骤:
- str = O.toString();
- 如果str为原始值,返回str;
- val = O.valueOf();
- 如果val为原始值,返回val;
- 抛出一个 TypeError 异常。
当用 Number hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:
- val = O.valueOf();
- 如果val为原始值,返回val;
- str = O.toString();
- 如果str为原始值,返回str;
- 抛出一个 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 运算流程如下:
- 令 lprim 为 ToPrimitive(lval).
- 令 rprim 为 ToPrimitive(rval).
- 如果 Type(lprim) 为 String 或者 Type(rprim) 为 String,则: 返回由 ToString(lprim) 和 ToString(rprim) 连接而成的字符串.
- 返回将加法运算作用于 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 的 - * / 运算符流程如下:
- 令 lnum 为 ToNumber(lval).
- 令 rnum 为 ToNumber(rval).
- 返回 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) |
|
|
例子:
[] == {}
-> 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隐式类型转换(详解 +,-,*,/,==)的更多相关文章
- javascript隐式转换详解
Javascript是web前端开发的必学技术,今天和大家分享的就是javascript的基础知识隐式转换,希望可以帮助大家更好的学习. 转换成布尔类型假 undefined->falSe nu ...
- Scala进阶之路-Scala高级语法之隐式(implicit)详解
Scala进阶之路-Scala高级语法之隐式(implicit)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们调用别人的框架,发现少了一些方法,需要添加,但是让别人为你一 ...
- JavaScript 隐式类型转换
JavaScript 隐式类型转换 原文:https://blog.csdn.net/itcast_cn/article/details/82887895 · 1.1 隐式转换介绍 · 1.2 隐式转 ...
- 有趣的JavaScript隐式类型转换
JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加.之所以不同的数据类型之间可以做运算,是因为 ...
- 四种JavaScript隐式类型转换的总结
一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被 ...
- 对存在JavaScript隐式类型转换的四种情况的总结
一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被 ...
- JavaScript 隐式类型转换之:加号+
加号+,有些情况下,它是算术加号,有些情况下,是字符串连接符号 如果字符串和数字相加,JavaScript会自动把数字转换成字符,不管数字在前还是字符串在前 "2" + 3; // ...
- 「译」JavaScript 的怪癖 1:隐式类型转换
原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...
- JavaScript学习总结(二、隐式类型转换、eval())
一.(避免)隐式类型转换 console.log(false == 0); //logs true; console.log(false === 0); //logs false; conso ...
随机推荐
- Handler机制中的消息队列
--> 学习自蘑菇街大佬 Handler机制可以看成是一个消息阻塞队列,当有消息时立即处理消息,没有消息时则阻塞.在Android系统中APP启动后很快进入死循环,不断读取MessageQueu ...
- webgrind安装使用详细说明
webgrind是一个网页版的性能分析工具,它的主要作用就是分析xdebug生成的cachegrind文件,以一种界面友好详尽的方式来展示性能数据.试用了一下感觉还是很不错的,鉴于网上并没有一个系统介 ...
- Windows下使用swoole的环境搭建
Cygwin 官方地址:http://www.cygwin.com/ swoole 官方下载地址:https://github.com/swoole/swoole-src/releases 方法/步骤 ...
- 云服务器之——Linux下配置JDK环境
在Linux下jdk的安装已经操作了很多次,每次发现自己还是会忘记之前的操作,所以今天就简单的来做个记录. 第一步:下载jdk安装包 登录oracle官网:https://www.oracle.com ...
- 网易与Google合作,于GDC开幕首日发布开源UI自动化测试方案
[TechWeb报道]美西时间3月19日,在GDC开幕第一天的Google开发者专场,Google发布了一款由网易研发的UI自动化测试方案:Airtest Project. Google方面评价,这可 ...
- javaSE复习之——线程
线程其实就是程序执行的一条路径,一个进程中可以包含多条线程,多线程并发执行可以提高程序效率,可以同使完成多项任务 多线程的应用场景 迅雷多线程一起下载 服务器同时处理多个客户请求 多线程原理(单核CP ...
- 吴裕雄--天生自然 PYTHON数据分析:威斯康星乳腺癌(诊断)数据分析(续一)
drop_list1 = ['perimeter_mean','radius_mean','compactness_mean','concave points_mean','radius_se','p ...
- Android 一个3D相册源码
我们专业课有Android的学习,最后老师让做一个简单的Android应用程序.我在网上找些资料,加上自己改造一下做了一个3D相册. 程序仿照Android的相册功能,调用Gallery类对相片进行浏 ...
- Android apk签名详解——AS签名、获取签名信息、系统签名、命令行签名
Apk签名,每一个Android开发者都不陌生.它就是对我们的apk加了一个校验参数,防止apk被掉包.一开始做Android开发,就接触到了apk签名:后来在微信开放平台.高德地图等平台注册时,需要 ...
- c++中的函数重载、函数重写、函数重定义
目录 一.函数重载 二.函数重写 三.函数重定义 为了更加深刻的理解 函数重载.重写.重定义,我们可以带着如下这两个问题去思考: 1.子类中是否可以定义父类中的同名成员?为什么? 可以,因为子类与父类 ...