持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
在typescript还没出现之前,我相信不少伙伴对于javascript中的类型转换有点丈二和尚摸不着头脑,好比为啥'1' + 1 = '11'而1 + '1' = 2 ;那么今天我们就来好好梳理一下javascript这门语言中的类型转换,如果不是很明白javascript中有哪些类型,可以看看笔者之前写过的文章JS中令人疑惑的数据类型及其判断方法,相信看完对你学习本章内容有些许的帮助,那么,我们开始本章的学习吧。
原始类型转原始类型
原始值转布尔类型
首先布尔类型是怎么来的呢?是我们通过调用构造函数Boolean,new出一个实例对象,也就是说 new Boolean() 得到的 ,默认得到的是false,即 { Boolean : false },那我们看看原始值转成布尔类型会是什么?
- 字符串转布尔类型,只有空字符串即
Boolean('')得到的是false,其他所有的字符串转布尔类型得到的都是true; - 数字类型转布尔类型,
Boolean(0)和Boolean(NaN)这两个转成布尔值为false,其他都为true(通常我们不将NaN作为一种特殊的数据类型,而是作为数字类型的一种特殊的数据格式); - 布尔值转布尔值,虽然听起来有点有病的味道,但是人家虽然无意义,但确实合法,即
Boolean(false)得到false,Boolean(true)得到true; - null 和 undefined 这两种类型转成布尔值都的得到
false。
我们可以浅浅总结一下:原始值转布尔类型,有这五种情况得到的值为false,即空字符串、数字0、false本身、null以及undefined,其他情况基本为true。
原始值转数字类型
数字类型也是调用构造函数Number, new 一个实例对象出来new Number() 得到的是数字0,那将原始值转成数字类型呢?
- 字符串类型转数字类型,只有
字符串类型的数字转成数字类型可以转成对应的数字类型,其他非数字类型的字符串转成数字,只能得到NaN,即Number('123') --> 123;Number('abc') --> NaN; - 数字类型转数字类型,数字类型转数字类型得到的就是本身(合法但无意义);
- 布尔值转数字类型,
Number(true) --> 1,Number(false) --> 0; - null转数字类型,
Number(null) --> 0(特例需要记住); - undefined转数字类型,
Number(undefined) --> NaN;
实际上Number这个构造函数内部是使用了ToNumber()方法使得其他类型的转化为数字类型的,但是javascript中,源码封装好的是我们不能使用ToNumber(),仅在Number这个构造函数内部调用。
原始值转字符串类型
既然boolean和字符串类型都是 new 他们构造函数的实例对象得到的,那我字符串是不是也可以呢? 当然可以字符串类型也可以看做 new String () 默认得到的是空字符串'',原始值转字符串类型呢?
- 字符串转字符串类型,字符串类型转字符串类型,得到字符串本身,
String('abc') --> 'abc',(合法但无意义); - 数字转字符串类型,数字类型转字符串得到字符串类型的数字,
String(123) --> '123',String(Infinity) --> 'Infinity',String(NaN) --> 'NaN'。 - 布尔值转字符串类型,
String(true) --> 'true',String(false) --> 'false'。 - null转字符串类型
String(null) --> 'null'; - null转字符串类型
String(undefined) --> 'undefined'。
原始值转对象
原始值转对象其实很简单,我们只需要理解一句话,那就是 new 一个构造函数得到的是实例对象,
let a = 'abc'
let b = new String(a);
console.log(typeof b);
对象转原始类型
同理数字类型和布尔值转对象一样是new 他们的构造函数,得到的就是他们本身的包装类对象,即:
new String() | new Number() | new Boolean()
对象转布尔值
所以所有的引用类型转成布尔值得到的都为true
Object => String,对象本身具备一个ToPrimitive方法,在javascript的源码并没有暴露出来给我们使用,它的原理是ToPrimitive(input,PreferredType) input是输入的值,preferedType是期望转换的类型,他可以是字符串,也可以是数字。
所以对象转成字符串或者数字就相当于对象调用了ToPrimitive(input,PreferredType),当第一个参数input是Date类型,第二个参数不传,默认第二个参数为String。
valueOf() 方法返回指定对象的原始值。
toString() 方法返回一个表示该对象的字符串。
对象转数字类型
ToPrimitive(obj,Number)
- 如果obj是基本类型,直接返回;
- 否则,调用valueOf方法,如果得到一个原始类型,则返回;
- 否则,调用toString方法,如果得到一个原始类型,则返回;
- 否则报错。
对象转字符串类型
ToPrimitive(obj,String)
- 如果obj是基本类型,直接返回;
- 否则,调用toString方法,如果得到一个原始类型,则返回;
- 否则,调用valueOf方法,如果得到一个原始类型,则返回;
- 否则报错。
我们来实际操练一下:
Number({})
首先我们要明确,这个例子是要将空对象转数字类型;
所以第一步{}不是基本类型,直接返回;
第二步调用valueOf方法,得到的还是一个{}(空对象);
第三步调用toString方法,得到一个"[object Object]"(字符串)。
因为Number是要得到一个数字类型的值,此时只得到了字符串类型,
所以第五步字符串类型转数字类型,即得到的值最终为NaN。
这只是其中一个较为好理解的,不要盲目的觉得你都理解了,那Number( [ ] )得到的结果是啥呢?
再聊接下来的内容之前我们需要知道两个方法:
JSON.stringify()方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。JSON.parse()方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象。提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换 (操作)。
一元操作符 +
当 + 运算作为一元操作符时,会调用ToNumber()处理该值
+[] //0
+['1'] // 1
+['1','2','3'] --> '1,2,3' --> NaN
+{} --> "[object Object]" --> NaN
二元操作符 +
v1 + v2 --> ToPrimitive(v1) + ToPrimitive(v2)
- lprim = ToPrimitive(v1);
- rprim = ToPrimitive(v2);
- 如果lprim 是字符串或 rprim是字符串,那么返回ToString(lprim) + ToString(rprim)的拼接结果;
- 返回 ToNumber(lprim) 和 ToNumber(rprim)的相加结果。
1 + '1' // '11'
null + 1 // 1
[] + [] // ''
[] + {} // '' + "[object Object]" --> "[object Object]"
{} + [] // 0 (谷歌V8引擎将{}识别为独立的代码块,而不是作为一个对象)
({} + []) // "[object Object]" + ''--> "[object Object]"
{} + [] // 0是因为谷歌浏览器识别为:
{
}
// 上面为一个代码片段
+[]
// 下面为一个一元操作符+ 所以转化为0
{} + {} 它的结果取决于浏览器的内核是将第一个{}看作是块级代码 --> NaN 还是空对象 --> "[object Object][object Object]"
//
==
== 会比较两边值是否相等,若不是同一种数据类型会进行隐式类型转换;
当执行 x == y
-
如果 x 和 y 是同一类型
-
x 是 undefined ,返回true
-
x 是 null ,返回true
-
x 是数字
x 是 NaN , 返回false(NaN == NaN // false)
-
x 和 y 指向同一个对象(同一个引用地址),返回 true 否则 返回 false
-
-
如果 x 和 y 不是同一类型 (null == undefined // true)
特例 -
1 == 'h' --> 1 == ToNumber('h')
-
false == '1' --> ToNumber(false) == ToNumber('1')
-
true == {a: 1} // ToPrimitive({a: 1}) --> 1 == NaN // false
[ ] == ![ ] //true
看到上面这个例子相信你会和我一样一脸茫然,为什么这还能为true呢?首先我们要知道一个运算符优先级 - JavaScript | MDN (mozilla.org)
[] == ![] //true
1. !天生是为布尔值所准备的取反,所以现将[]转化为布尔值,即true !true --> false
[] == false
2. ToNumber(false) --> 0
[] == 0
3. ToPrimitive(obj,Number)
'' == 0
4. '' --> 0 ,字符串转数字类型
0 == 0
所以答案是true
相信学习到这你和我一样,对javascript这门语言中的类型转换有了一定的了解,希望这篇文章能够帮助到你,有任何问题欢迎评论区留言互动,感谢你的观看!