我们在写一些判断语句中,经常会使用== 和 ===符号来判断是否相等,但是这两个符号究竟有什么不一样呢?这就要了解JS的类型转换了,话不多说,直接涨知识!
一、类型转换方式
JavaScript中实现类型转换通常有两种方式:显式类型转换和隐式类型转换。
1. 显式类型转换
JavaScript通过调用特定的方法或使用函数来显式转换类型,例如直接调用toString()、String()、Boolean()等函数。
2. 隐式类型转换
JavaScript在需要时会自动将引用类型转换为原始类型,这种转换就叫做隐式类型转换。通常发生的场景有:
- 四则运算
+-*/% - 判断语句
if()while()==><<=>=!=
所以,在JavaScript中,判断相等有两种情况:
==会发生隐式类型转换,所以只判断值是否相等===不会发生隐式类型转换,意味着需要判断值和类型是否都相等,也叫全等于。
二、原始类型转原始类型
1. Boolean() - 转换为布尔值
原始类型转换为布尔类型时:Number类型里面只有0和无效数字NaN会转换为false,另外空字符串转布尔类型也是false,其他都是true。不论显示转换还是隐式转换,我们都可以详细对照官方文档给的表格进行转换,如下:
测试代码如下:
// 显示转换
console.log(Boolean(1)); // true
console.log(Boolean(true)); // true
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
console.log(Boolean(-1)); // true
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('gagiuq')); // true
console.log(Boolean('')); // false
// 隐式转换
let arr = [1]
if(arr.length){ // 隐式类型转换成布尔类型 arr.length = 1 --> true
console.log('hello'); // hello
}
2. Number() —— 转数字
Number类型包括:有效数字和无效数字NaN,而Number() 函数可以将值直接转换为数字,我们可以直接根据官方文档给出的表格进行判断:
其中我们能够看到对于字符串转数字时,是有不同的结果:
- 空字符串/空白符转数字,返回数字0
- 纯数字字符串转数字,返回该数字
- 非纯数字的字符串转数字:NaN
- 带进制的数字字符串转数字:(0x、0X、0o、0O、0b、0B)转换成十进制数字
测试代码如下:
// 转数字类型
console.log(Number('1')); // 1
console.log(Number('0')); // 0
console.log(Number('')); // 0
console.log(Number(undefined)); // NaN
console.log(Number(null)); // 0
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(1)); // 1 没有转换
console.log(Number('hello')); // NaN
console.log(Number('123hello')); // NaN
console.log(Number("0x77")); // 119
console.log(Number("0xda")); // 218 0x/0X是十六进制数
console.log(Number("0o77")); // 63 0o/0O是八进制数
console.log(Number('0b101')); // 5 0b/0B是二进制数
3. String() —— 转换为字符串
String() 可以将任意类型的值转化成字符串,原始类型直接就是将数值以字符串的形式返回。
测试代码如下:
// 显式转字符串
console.log(String(1)); // '1'
console.log(String(undefined)); // 'undefined'
console.log(String(null)); // 'null'
console.log(String(true)); // 'true'
console.log(String(false)); // 'false'
console.log(String(NaN)); // 'NaN'
三、引用类型转原始类型
1. 引用类型转布尔:true
官方文档说的:引用类型转布尔值就只会返回true。
2. 引用类型转字符串
引用类型转字符串可以使用String(obj) 或者 Object.prototype.toString(obj),原理是:
- ToString({})
- ToPrimitive({}, String)。 其实看到已经有点懵逼,我们先放一边,来看一段代码:
// 对象转换字符串
let a = {}
console.log(String(a)); // [object Object]
console.log(a.toString()); //[object Object]
console.log(a.__proto__ === Object.prototype); // true
首先我们看对象转换字符串的代码,可以看出String(a) 和 a.toString()返回的结果都是一样的,而且这个字符串有点眼熟!
没错在前面一篇文章中(JavaScript中的类型判断方法你知道几种?- 掘金),我们已经提到了Object.prototype.toString()方法去判断数据类型,返回的字符串就是[object Object]这种状态。这里调用的toString()是打造在Object的原型上的,a是可以访问到的。
我们再看第二段代码:
// 数组转换成字符串
let b = []
console.log(b.toString()); // ''
console.log(Array.prototype == b.__proto__); // true
console.log(Object.prototype == Array.prototype.__proto__); // true
let arr = [1, 2, 3]
console.log(arr.toString()); // '1,2,3'
我们定义一个数组,从4、5行代码的原型链查找结果我们就可以看出,数组也是一个对象,所以它也是可以访问toString()方法的。理论上,如果b.toString访问的是Object.prototype.toString的话,应该是得到[object Array],但是结果却是空字符串,并且在第8行代码中返回的是一个数组元素以逗号拼接的字符串,所以应该是数组自身的隐式原型上存在一个toString()方法,如图:
同理,函数也是一个对象,如果函数自身的隐式原型上也存在一个toString方法,在函数调用它时也不会返回[object Funtion]字符串,我们看测试代码:
// 函数转字符串
let fn = function(){}
console.log(fn.toString()); // function(){}
代码结果已经显而易见了:函数自身的隐式原型上也存在一个toString方法。另外,我们还有其他引用类型,例如date,结果如图:
我们会发现date类型的toString()返回的结果状态和function类型是一样的,其实剩下的引用类型转字符串的状态也和这个相同。
由此可得,引用类型转字符串就是三种结果:
- {}.toString 会返回由 '[object' 和 class 和 ']' 组成的字符(返回对象的类型)
- [].toString 返回由数组中元素以逗号拼接的字符串
- xx.toString 直接返回 xx 的字符串字面量
3. 引用类型转数字 —— Number(obj)
原理:
- ToNumber({})
- ToPrimitive({}, Number)
- 使用完ToPrimitive({}, Number)会转换成原始类型,然后就是开始原始类型转number的操作
我们看第一步,官方解释ToNumber({})传入一个对象会做什么?如图:
根据文档提到的,会让这个对象作为一个参数,即V8会调用ToPrimitive({}, Number)方法,而在调用这个方法时内部会将对象转成字符串然后输出,然后再进行字符串转number类型。
如图就是将数组转成了字符串'1,2,3',然后再转数字就是NaN。
4. ToPrimitive
我们发现,在引用类型转字符串或者数字时,都调用了ToPrimitive(),最后返回相应的结果。
ToPrimitive接收两个参数,一个是需要转换类型的对象,第二个是String或者Number,即想转换的类型。具体执行步骤如下:
所以,
ToPrimitive(obj, String) 和 ToPrimitive(obj, Number)只是内部的valueOf() 和 toString()在执行顺序上面不一样。上面的翻译有点乱,我的总结如下:
(1) ToPrimitive(obj, String)
- 如果obj是原始类型,直接返回;
- 否则,调用toString(),如果得到原始类型则返回;
- 否则,valueOf(),如果得到原始类型则返回;
- 否则,报错。
(2)ToPrimitive(obj, Number)
- 如果obj是原始类型,直接返回;
- 否则,valueOf(),如果得到原始类型则返回;
- 否则,调用toString(),如果得到原始类型则返回;
- 否则,报错。
四、一元、二元运算符
1. 一元运算符 +
在 JavaScript 中,一元运算符(Unary Operators)是指仅作用于一个操作数的运算符,它的作用是把该操作数转换成number类型进行计算。(ToNumber())
例如:
console.log( +'123' ); // 123
2. 二元运算符(加法运算符)
在 JavaScript 中,二元运算符(Binary Operators)是指作用于两个操作数的运算符。常见的二元运算符包括算术运算符、比较运算符、逻辑运算符等。
我们这里以val1 + val2为例,官方文档给出的步骤如下:
(1)lprim = ToPrimitive(val1)
(2)rprim = ToPrimitive(val2)
- 如果lprim 或者 rprim 是字符串,另一个值直接ToString(),即就是字符串的拼接,例如:123 + 'hello' = 123hello
- 否则,返回对 ToNumber(lprim) 和 ToNumber(rprim) ,返回加法运算的结果。
OK,到这里就结束啦!!!终于写完了哈哈哈哈,喜欢的话,记得点个赞喔~谢谢!下次见