【JavaScript】类型转换

128 阅读5分钟

首先来看一个代码示例:

let a = 1
let b = '1'
console.log(a == b) // true
console.log(a === b) // false

可以发现,第三行代码始终输出为true,第四行代码始终为false

按人为判断知道字符型和数字型不可能相等,所以其实这里藏着一个js中数据类型转换的问题

== vs ===

  1. == 会发生隐式类型转换,所以只判断值是否相等
  2. === 不会发生类型转换,所以会判断值和类型是否相等

那么接下来我们步入正题:js中的类型转换

类型转换 --转换规则参照表

类型转换分为显式类型转换隐式类型转换

显式转换和隐式转换它们的转换的原理是一样,只看当前的代码场景进行选择

显式类型转换

  1. 转布尔Boolean(x)
console.log(Boolean()); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(null)); // false
console.log(Boolean(0));   // false
console.log(Boolean(-0));  // false
console.log(Boolean(-1));  // true
console.log(Boolean(NaN));  // false
console.log(Boolean(''));  // false
console.log(Boolean('abc'));  // true
  1. 转数字Number(x)
console.log(Number('123'));  // 123
console.log(Number(''));  // 0
console.log(Number('hello')); // NaN
console.log(Number());  // 0
  1. 转字符串String(x)
console.log(String(-1));  // -1

隐式类型转换

隐式转换是在js执行某些操作时自动发生的转换,比如在比较运算符使用等场景下(对象原始值通常发生隐式转换)。

隐式转换分类

  • 原始类型转原始类型
  • 引用类型转原始类型
    1. 转布尔 --- 任何引用类型转布尔都是true
    2. 转字符串 --- String(obj) => ToString(obj)=> ToPrimitive(obj, String)
    3. 转数字 --- Number(obj) => ToNumber(obj) => ToPrimitive(obj, Number)
必要知识
valueOf()
  • valueOf在对象的原型上,它只能将包装类的对象转为原始类型
let numObj = new Number(123);
console.log(numObj.valueOf()); // 123

let strObj = new String('hello');
console.log(strObj.valueOf()); // "hello"
toString()
  • js中大部分的构造函数原型上都重写了 toString 方法,且复杂类型转原始类型必须用toString方法
  1. 对象:{}.toString 返回由'[object' 和 [[class]] 和 ']' 组成的字符串:[object class]
  2. 数组:[].toString 返回由数组中每个元素以逗号拼接而成的字符串:[1,2,3]=>"1,2,3"
  3. 其他:xxx.toString 直接返回xxx的字符串字面量
  console.log({}.toString());    // "[object Object]"
  
  let map = new Map();
  console.log(map.toString());   // "[object Map]"
  
  let set = new Set();
  console.log(set.toString());   // "[object Set]"
  
  console.log([].toString());    //''
  console.log([123].toString());   //'1,2,3'
  
  function myFunction() { return 'Hello'; }
  console.log(myFunc.toString());        // "function myFunction() { return 'Hello'; }"
  
  console.log((new Date()).toString());  // "Wed Sep 11 2024 00:14:53 GMT+0800 (中国标准时间)"
  
  let numObj = new Number(123);
  console.log(numObj.toString()); // "123"
ToPrimitive(obj,type) --ES5参考文档
  • ToPrimitive(obj, String)

    1. 判断obj是否为原始类型,是则直接返回
    2. 否则,调用toString(),如果得到了原始类型,则返回
    3. 否则,调用valueOf(),如果得到了原始类型,则返回
    4. 否则,抛出TypeError异常
  • ToPrimitive(obj, Number)

    1. 判断obj是否为原始类型,是则直接返回
    2. 否则,调用valueOf(),如果得到了原始类型,则返回
    3. 否则,调用toString(),如果得到了原始类型,则返回 (调换顺序是出于性能考虑)
    4. 否则,抛出TypeError异常

发生隐式类型转换的场景

  1. 四则运算 + - * / %
  2. 判断语句 if while == >= <= != > <
加法运算符+ --ES5参考文档
  1. 作为一元运算符 -- 会发生隐式类型转换,转成number

  2. 作为二元运算符 -- 只要+左右两边有一个是字符串,另一个也会转为字符串进行拼接

先来感受一下:

let a = + "123";
console.log(+"123"); // 123
console.log(typeof a);  // number

可以看到,js引擎在执行这份代码时,自动将String类型的数据转为了number类型

console.log('' + {}); // [object,object]

原理如下:

在例1中,+作为一元运算符,会将数据转换成number类型

在例2中,+作为二元运算符,左边为字符类型导致右边也被转换成字符串拼接输出。根据规则{}会转为[object,object]进行输出

更多练习:

console.log(1 + '1');           // "11"
// 1 + '1' ==> '11'
// ToString(1) + '1'
// '1' + '1'`
// '11'

console.log(1 + 2);             // 3

console.log(null + 1)           // 1
// null + 1 ==> 1
// ToNumber(null) + 1
// 0 + 1
// 1

console.log({} + '1')            // '[object Object]1'
// ToPrimitive({} ,string) + '1'
// {}.toString() + '1'
// '[object Object]' + '1'
// '[object Object]1'

console.log([] + {})            // '[object Object]'
// ToPrimitive([],number)  + ToPrimitive({},number)
// [].valueOf() + {}.valueOf()==> [] + {}
// [].toString() + {}.toString()
// '' + '[object Object]'
// '[object Object]'

!运算符

!会先将后面的数据转换为布尔类型的值,再取反

 ==运算

==操作符会尝试将两边的操作数转换为同一类型后再进行比较,基本都是转换为数字类型,如果==两边有出现!先将含有!的一边转换为布尔类型。

案例1:

console.log([] == ![])

运算过程:

  1. 对象转布尔一定为true,则![] == false
  2. 证明:[] == false布尔值false转为数值为0
  3. [] == 0
  4. ToPrimitive([])==>toString([])==>''==>0
  5. 0 == 0
  6. true

案例2:

let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false

这是一道经典的面试题,运算过程和结果如下:

let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
// result应该是?

1.首先100 + true
+连接符两边存在Number类型,true转number为1,进行加法运算,结果为:101
2.101 + 21.2
+连接符两边均为Number类型,进行加法运算,结果为:122.2
3.122.2 + null
+连接符两边存在Number类型,null转number为0,进行加法运算,结果为:122.2
4.122.2 + undefined
+连接符两边存在Number类型,undefined转number为NaNNaN与任何数据类型计算都为NaN,结果为:NaN
5.NaN + "Tencent"
+连接符两边存在String类型,NaN转string为"NaN",进行字符串拼接,结果为:"NaNTencent"
6."NaNTencent" + []
+连接符两边存在String类型,[]转string为"",进行字符串拼接,结果为:"NaNTencent"
7."NaNTencent" + null
+连接符两边存在String类型,null转string为"null",进行字符串拼接,结果为:"NaNTencentnull"
8."NaNTencentnull" + 9
+连接符存在String类型,9转string为"9",进行字符串拼接,结果为:"NaNTencentnull9"
9."NaNTencentnull9" + false
+连接符存在String类型,false转string为"false",进行字符串拼接,结果为:"NaNTencentnull9false"