JavaScript类型转换总结与常见情况解析
类型转换是将值从一种类型转换为另一种类型的过程(比如字符串转数字,对象转布尔值等)
一、类型转换的分类
类型转换可以分为隐式类型转换和显式类型转换。
二者的区别显而易见:我们能够从代码中看出哪些地方是显式强制类型转换,而隐式强制类型转换则不那么明显,通常是某些操作产生的副作用。
例如:
var a = 42; var b = a + ""; // 隐式强制类型转换 var c = String( a ); // 显式强制类型转换
对变量 b 而言,强制类型转换是隐式的;由于 + 运算符的其中一个操作数是字符串,所以是字符串拼接操作,结果是数字 42 被强制类型转换为相应的字符串”42“。
而 String() 则是将 a 显示强制类型转换为字符串。
严格相等运算符(===)不会触发类型隐式转换,所以它可以用来比较值和类型是否都相等。
隐式类型转换是一把双刃剑,使用它虽然可以写更少的代码但有时候会出现难以被发现的bug。
二、类型转换分析
1、Boolean 类型转换
在条件判断时,除了 undefined,null,false,NaN,' ',0,-0,其它所有值都转为 true,包括所有对象。
Boolean() 方法可以用来显式将值转换成 boolean 型。
隐式类型转换通常在逻辑判断或者有逻辑运算符时被触发(|| && !)
Boolean(2) // 显示类型转换
if(2) {} // 逻辑判断触发隐式类型转换
!!2 // 逻辑运算符触发隐式类型转换
2 || 'hello' // 逻辑运算符触发隐式类型转换
2、String 类型转换
String() 方法可以用来显式将值转为字符串,隐式转换通常在有 + 运算符并且有一个操作数是 string 类型时被触发,如:
String(123) // 显式类型转换 123 + '' // 隐式类型转换
Symbol 类型转 String 类型是比较严格的,它只能被显式的转换
String(Symbol('symbol')) // 'Symbol(symbol)' '' + Symbol('symbol') // TypeError is thrown
3、Number 类型转换
和 Boolean()、String() 方法一样, Number() 方法可以用来显式将值转换成 number 类型。
number 的隐式类型转换是比较复杂的,因为它可以在下面多种情况下被触发。
- 比较操作(>, <, <=, >=)
- 按位操作(| & ^ ~)
- 算数操作(- + * / %)--- 注意:当 + 操作存在任意的操作数是 string 类型时,不会触发 number 类型的隐式转换
- 一 元 + 操作
- 非严格相等操作(== 或者 !== )--- 注意:== 操作两个操作数都是 string 类型时,不会发生 number 类型的隐式转换
Number('123') // 显示类型转换
+ '123' // 隐式类型转换
123 != "456" // 隐式类型转换
4 > "5" // 隐式类型转换
5 / null // 隐式类型转换
true | 0 // 隐式类型转换
这里有 2 个特殊的规则需要记住:
- 当将 == 应用于 null 或 undefined 时,不会发生数值转换。null 只等于 null 或 undefined,不等于其他任何值。
null == 0 // false, null is not converted to 0
null == null // true
undefined == undefined // true
null == undefined // true
undefined == 0 // false
- NaN 不等于任何值,包括它本身
NaN === NaN // false
4、object 类型转换
到这里我们已经深入了解了原始类型的转换,接下来我们来看一下对象转原始类型。
对象在转换类型时,会调用内置的 [[ToPrimitive]] 函数,对于该函数来说,算法逻辑一般如下:
- 如果已经是原始类型了,那就不需要转换了
- 如果需要转字符串类型就调用 x.toString(),结果为基础类型则返回转换的值;非字符串类型则先调用 valueOf,结果非基础类型再调用 toString
- 调用 x.valueOf() ,如果转换为基础类型,则返回转换的值
- 如果都没有返回原始类型,就会报错
当然也可以重写 Symbol.toPrimitive,该方法在转原始类型时调用优先级最高:
let a = {
valueOf() {
return 0
},
toString() {
return '1'
},
[Symbol.toPrimitive]() {
return 2
}
}
1 + a // => 3
5、四则运算符
加法运算符不同于其他几个运算符,它有以下两个特点:
- 特点一:运算中其中一方为字符串,那么就会把另一方也转换为字符串
- 特点二:如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
1 + '1' // '11'
true + true //
4 + [1,2,3] // "41,2,3"
如果你对于答案有疑问的话,请看解析:
- 对于第一行代码来说,触发特点一,所以将数字
1
转换为字符串,得到结果'11'
- 对于第二行代码来说,触发特点二,所以将
true
转为数字1
- 对于第三行代码来说,触发特点二,所以将数组通过
toString
转为字符串1,2,3
,得到结果41,2,3
另外对于加法还需要注意这个表达式 'a' + + 'b'
'a' + + 'b' // -> "aNaN"
因为 + 'b'
等于 NaN
,所以结果为 "aNaN"
,你可能也会在一些代码中看到过 + '1'
的形式来快速获取 number
类型。
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字
4 * '3' //
4 * [] //
4 * [1, 2] // NaN
6、比较运算符
- 如果是对象,就通过
toPrimitive
转换对象 - 如果是字符串,就通过
unicode
字符索引来比较
let a = {
valueOf() {
return 0
},
toString() {
return '1'
}
}
a > -1 // true
在以上代码中,因为 a
是对象,所以会通过 valueOf
转换为原始类型再比较值。
7、== VS ===
对于 ==
来说,如果对比双方的类型不一样的话,就会进行类型转换,流程如下:
(1)首先判断两者类型是否相同。相同的话就是比大小了
(2)类型不相同的话,则进行类型转换
(3)会先判断是否在对比 null 和 undefined,是的话就会返回 true
(4)判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
1 == '1'
↓
1 == 1
(5)判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
'1' == true
↓
'1' == 1
↓
1 == 1
(6)判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
'1' == { name: 'yck' }
↓
'1' == '[object Object]'
对于 ===
来说就简单多了,就是判断两者类型和值是否相同
三、18 种常见情况解析
1、常见情况
true + false //
'+' 运算符会触发 number 类型转换对于 true 和 false
2、常见情况
12 / '6' //
算数运算符会把字符串 ‘6’ 转为 number 类型
3、常见情况
"number" + 15 + 3 // "number153"
'+' 运算符按从左到右的顺序的执行,所以优先执行 “number” + 15, 把 15 转为 string 类型,得到 “number15” 然后同理执行 “number15” + 3
4、常见情况
15 + 3 + "number" // "18number"
15 + 3 先执行,运算符两边都是 number 类型 ,不用转换,然后执行 18 + “number” 最终得到 “18number”
5、常见情况
[1] > null // true ==> '1' > 0
==> 1 > 0
==> true
比较运算符 > 执行 number 类型隐式转换。
6、常见情况
"foo" + + "bar" // "fooNaN" ==> "foo" + (+"bar")
==> "foo" + NaN
==> "fooNaN"
一元 + 运算符比二元 + 运算符具有更高的优先级。所以 + bar表达式先求值。一元加号执行字符串“bar” 的 number 类型转换。因为字符串不代表一个有效的数字,所以结果是NaN。在第二步中,计算表达式'foo' + NaN
7/8、常见情况
'true' == true // false ==> NaN == 1
==> false 'false' == false // false ==> NaN == 0
==> false
== 运算符执行 number 类型转换,'true' 转换为 NaN, boolean 类型 true 转换为 1
9、常见情况
null == '' // false
null 不等于任何值除了 null 和 undefined
10、常见情况
!!"false" == !!"true" // true ==> true == true
==> true
!! 运算符将字符串 'true' 和 'false' 转为 boolean 类型 true, 因为不是空字符串,然后两边都是 boolean 型不在执行隐式转换操作。
11、常见情况
['x'] == 'x' // true
== 运算符对数组类型执行 number 转换,先调用对象的 valueOf() 方法,结果是数组本身,不是原始类型值,所以执行对象的 toString() 方法,得到字符串 'x'
12、常见情况
[] + null + 1 // 'null1' ==> '' + null + 1
==> 'null' + 1
==> 'null1'
'+' 运算符执行 number 类型转换,先调用对象的 valueOf() 方法,结果是数组本身,不是原始类型值,所以执行对象的 toString() 方法,得到字符串 '', 接下来执行表达式 '' + null + 1
13、常见情况
0 || "0" && {} // {} ==> (0 || '0') && {}
==> (false || true) && true
==> true && true
==> true
逻辑运算符 || 和 && 将值转为 boolean 型,但是会返回原始值(不是 boolean)
14、常见情况
[1,2,3] == [1,2,3] // false
当运算符两边类型相同时,不会执行类型转换,两个数组的内存地址不一样,所以返回 false
15、常见情况
{} + [] + {} + [1] // '0[object Object]1' ==> +[] + {} + [1]
==> 0 + {} + [1]
==> 0 + '[object Object]' + '1'
==> '0[object Object]1'
所有的操作数都不是原始类型,所以会按照从左到右的顺序执行 number 类型的隐式转换, object 和 array 类型的 valueOf() 方法返回它们本身,所以直接忽略,执行 toString() 方法。 这里的技巧是,第一个 {} 不被视为 object,而是块声明语句,因此它被忽略。计算从 +[] 表达式开始,该表达式通过toString()方法转换为空字符串,然后转换为0
16、常见情况
! + [] + [] + ![] // 'truefalse' ==> !(+[]) + [] + (![])
==> !0 + [] + false
==> true + [] + false
==> true + '' + false
==> 'truefalse'
一元运算符优先执行,+[] 转为 number 类型 0,![] 转为 boolean 型 false
17、常见情况
new Date(0) - 0 // ==> 0 - 0
==> 0
'-' 运算符执行 number 类型隐式转换对于 Date 型的值,Date.valueOf() 返回到毫秒的时间戳
18、常见情况
new Date(0) + 0 // 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0' ==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)' + 0
==> 'Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0'
'+' 运算符触发默认转换,因此使用 toString() 方法,而不是 valueOf()
JavaScript类型转换总结与常见情况解析的更多相关文章
- 前端开发:Javascript中的数组,常用方法解析
前端开发:Javascript中的数组,常用方法解析 前言 Array是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array ...
- 移动Web开发图片自适应两种常见情况解决方案
本文主要说的是Web中图片根据手机屏幕大小自适应居中显示,图片自适应两种常见情况解决方案.开始吧 在做配合手机客户端的Web wap页面时,发现文章对图片显示的需求有两种特别重要的情况,一是对于图集, ...
- Java OOM 常见情况
Java OOM 常见情况 原文:https://blog.csdn.net/qq_42447950/article/details/81435080 1)什么是OOM? OOM,全称“Out Of ...
- 常见bug解析-移动端
手机测试常见bug解析 1.测试时遇到“手机无响应”? 有以下几个原因: a.手机内存不足 b.android进程之间死锁引起的(就是两个进程之间) c.手机的CPU运行高引起的 可以查看手机的崩溃日 ...
- 松软科技Web课堂:JavaScript 类型转换
Number() 转换数值,String() 转换字符串,Boolean() 转换布尔值. JavaScript 数据类型 JavaScript 中有五种可包含值的数据类型: 字符串(string) ...
- 移动站Web开发图片自适应两种常见情况解决方案
本文主要说的是Web中图片根据手机屏幕大小自适应居中显示,图片自适应两种常见情况解决方案.开始吧 在做配合手机客户端的Web wap页面时,发现文章对图片显示的需求有两种特别重要的情况,一是对于图集, ...
- javascript:void(0);用法及常见问题解析
void 操作符用法格式: javascript:void (expression) 下面的代码创建了一个超级链接,当用户以后不会发生任何事.当用户链接时,void(0) 计算为 0,但 Javasc ...
- [CG编程] 基本光照模型的实现与拓展以及常见光照模型解析
0.前言 这篇文章写于去年的暑假.大二的假期时间多,小组便开发一个手机游戏的项目,开发过程中忙里偷闲地了解了Unity的shader编写,而CG又与shaderLab相似,所以又阅读了<CG教程 ...
- .Net 内存溢出(System.OutOfMemoryException)的常见情况和处理方式总结
.Net 内存溢出(System.OutOfMemoryException)的常见情况和处理方式总结 在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾 ...
随机推荐
- 【解决篇】映美FP-530K+打印发票卡纸,色带安装问题
之前由于色带变浅了,而换了色带,后来出现了发票经常中间卡纸的状况,不过也不是不能打,只是偶尔出现,发现每次打,发票纸会撞击一下色带,导致有时候发票会被色带挡一下,导致中间卡纸,有时候又能过去.后来通过 ...
- 【电商日志项目之六】数据分析-Hive方式
环境 hadoop-2.6.5 hive-1.2.1 一.Hive和Hbase整合如果使用Hive进行分析,Hive要从Hbase取数据(当然可以直接将数据存到Hive),那么就需要将Hive和HBa ...
- app内嵌h5页面在ios手机端滑动卡顿的解决方法
1.带滚动条的dom需加样式 -webkit-overflow-scrolling: touch;2.去掉 width:100%; height:100%
- python爬虫1
1 网页结构 html:超文本标记语言------->类似人的鼻子耳朵,长在那里,大体骨架就是那个样子 css:层叠样式表------->这个是外观的深化,比如贴个双眼皮,橙色眼睛... ...
- 手贱重置了mysql密码,导致登陆不进去的解决办法
上午手残,重置了下MySQL的密码,导致用命令登陆不进去 由于版本的问题,导致网上的方法都不可用 折腾了一上午,摸索+参考官方文档,终于搞定 利用--init-file 第一步,关掉系统服务 ...
- 深度解析qml引擎---(1)Qml文件加载
"美的事物是永恒的喜悦" --- 济慈 ...
- Appium移动端测试--搭建测试环境
目录 文章目录如下 安装Android Studio及Android SDK 更改VDM默认存储路径 通过npm安装Appium Server 启动Appium GUI模式 Appium连接会话 Ap ...
- Django项目常见面试问题
1.python中的lambda是什么意思,可以举例 匿名函数 a = lambda x:x+1 print(a(1)) 2.请写出以下代码执行的结果 class Parent(object): x ...
- 数据分析——matplotlib的用法
Matplotlib是一个强大的Python绘图和数据可视化的工具包.数据可视化也是我们数据分析的最重要的工作之一,可以帮助我们完成很多操作,例如:找出异常值.必要的一些数据转换等.完成数据分析的最终 ...
- quartz2.3.0(二)触发器Trigger花式Scheduler调度job
任务类 package org.quartz.examples.example2; import java.util.Date; import org.slf4j.Logger; import org ...