JavaScript类型转换探秘

263 阅读5分钟

前言:当代码开始"变脸"——类型转换的魔法与陷阱

在JavaScript的世界里,类型转换就像一场精彩的魔术表演:数字突然变成字符串,对象神秘地化为原始值,空数组竟能与0相等...这些看似魔法的行为背后,隐藏着严谨的语言规则。理解类型转换机制,是解锁JavaScript深层奥秘的关键钥匙。

作为前端开发者,你是否曾困惑于:

  • 为什么 [] == ![] 的结果是 true
  • 为什么 {} + [] 返回 0 而 [] + {} 返回 "[object Object]"
  • == 和 === 到底该在什么场景使用?

本文将深入剖析JavaScript的类型转换机制,通过生动的代码示例和原理图解,带你:

  1. 揭开 == 与 === 的神秘面纱
  2. 掌握显示与隐式类型转换的规则
  3. 破解 ToPrimitive 算法的运作原理
  4. 理解 valueOf() 和 toString() 的转换优先级
  5. 识别日常开发中的类型转换陷阱

准备好破解JavaScript的"变形魔法"了吗?让我们开始这段类型转换的探索之旅! 前置知识:类型判断(toString原理)

== vs ===

  1. == 会发生隐式类型转换,所以只判断值是否相等
  2. === 不会发生隐式类型转换,所以判断值和类型是否相等
let a=1
let b=2
let c='1'
console.log(a==b);
console.log(a==c);
console.log(a===c);

image.png

类型转换

  • 显示类型转换(原始数据类型之间转换)
  1. 转布尔 Boolean(x)

  2. 转数字 Number(x) es5.github.io/#x15.7.1.1

  3. 转字符串 String(x)

let a = 1;
let b = String(a);
let c = Boolean(a);
let d = "123";
let e = Number(d);
let f = Boolean(d);
console.log(a, b, c, e, f);
console.log(Boolean()); //false
console.log(Boolean(undefined)); //false
console.log(Boolean(null)); //false
console.log(Boolean(0)); //false
console.log(Boolean(NaN)); //false
console.log(Boolean("")); //false
console.log(Boolean("pp")); //true

console.log(Number(d)); //123
console.log(Number("")); //0
console.log(Number("ppp")); //NaN
console.log(Number(null));
console.log(Number(false));
console.log(Number(true));

image.png

image.png [相关链接](JavaScript 类型转换)

  • 隐式类型转换
  1. 原始类型转原始类型

  2. 引用类型转原始类型

    1. 转布尔 ---任何引用类型转布尔 都是true

    2. 转字符串 ---String(obj) ==>ToString(obj)==>ToPrimitive(obj,String)Toprimtive只针对Objcet类型

    3. 转数字 ---Number(obj) ==>ToNumber(obj)==>ToPrimitive(obj,Number)

引用类型转字符串:

let arr=[1,2,3,4]
console.log('hi'+arr);

image.png

Toprimitive

es5.github.io/#x8.12.8

  • Toprimitive(obj,String)

  • 1.判断obj是否为原始类型,是则直接返回

    3.否则,调用toString()方法,如果得到原始类型,则返回

    5.否则,调用valueOf()方法,如果得到原始类型,则返回

    7.否则,抛出typeError异常

  • ToPrimitive(obj,Number)

    1.判断obj是否为原始类型,是则直接返回

    3.否则,调用valueOf()方法,如果得到原始类型,则返回

    5.否则,调用toString()方法,如果得到原始类型,则返回

    7.否则,抛出typeError异常

valueof()

  • valueOf在对象的原型上(valueof()存在于object.prototype上面),它只能将包装类的对象转化为原始类型

image.png

包装类对象是指:这里我们想通过自带构造函数创建原始类型,但是通过构造函数创建时相当于创建对象,这个对象就叫包装类,valueof()可以将我们传入构造函数原始数据拿出来,相当于将包装类对象转换为原始类型。

image.png

三大类toString()

  • js中大部分的构造函数原型上都重写了toString方法(除了Set,Map)

1.{}.toString() 返回由'[objce'和[[class]]和 ']' 组成的字符串

2.[].toString() 返回由所有元素用逗号连接组成的字符串

3.xxx.toString() 直接返回xxx的字符串字面量(xxx其余数据类型)

image.png

console.log(1==[])

以上代码隐式转换过程:

Number([])==>toNumber([])==>toPrimitive([].number)

toPrimitive([],number):

valueof([])==>toString([]) 字符串的toString():返回数组所有元素逗号拼接的字符串,这里返回空字符串

return 原始数据类型''

原始类型的隐式转换:空字符串转数字为0

结果为false

发生隐式类型转换的场景有哪些

1.四则运算 +- * / % 2.判断语句 if while == >= <= != > <

+

es5.github.io/#x11.6.1

  1. 作为一元运算符 会发生隐式类型转化,转成number
  2. 作为二元运算符 只要加号左右两边有一个字符串,那么另一个也会转换为字符串 拼接

image.png

经典面试题:

[]==![]

[]==!true

[]==false

[]==0

''==0

0==0

v8执行以上几步,结果是true 有!将[]隐式转换为布尔类型,任何引用类型转布尔类型都是true,!ture就是false,因为==是判断值相等,所以等号两边会转化为数字类型,右边就是false转换为数字0,左边就是引用类型隐式转换为数字类型,执行Number() toNumber() toPrimitive() valueof() toString(),数组的toString()方法将数组转换为由逗号拼接的字符串,那么空数组转化为空字符串,空字符串又隐式转换为数字0

{}+[]

一开始的目标是向数字类型转化,因为有加号做四则运算,那么左边对象隐式类型转换为数字类型,先Number() 再到里面的toNumber() 再到里面的toPrimitive , 最后 到toPrimitive()里面的valueof(),再执行object类型的toString()方法返回的是字符串,此时左边为字符串,加号作为二元运算符 只要加号左右两边有一个字符串,那么另一个也会转换为字符串 拼接 ,右边也直接隐式转换为字符串,执行那三步,结果为'',最后字符串拼接

image.png

结语:掌握类型转换,编写更健壮的代码

经过本文的探索,我们揭开了JavaScript类型转换的神秘面纱:

  • == 与 === 的选择:在需要精确控制的场景使用 ===,在允许灵活转换时使用 ==
  • 隐式转换的陷阱:特别注意数学运算和比较运算中的自动转换
  • 对象转换的规则:牢记 ToPrimitive 算法中 valueOf 和 toString 的调用顺序