第十九天:类型转换与比较 — JS 中最容易踩坑的地方
蜗牛往上爬 · 前端工业可视化学习笔记 第 19 篇
昨天学了变量和六大数据类型,今天深入 JS 最"坑"的两块:类型转换和比较运算。"5" + 3等于"53"但"5" - 3等于2?==和===到底有什么区别?把这些搞清楚,能避免 80% 的 JS 初级 bug。
目录
一、显式类型转换
显式转换 = 你主动调用函数去转换类型。
转为字符串
console.log(String(123)); // "123"
console.log(String(true)); // "true"
console.log(String(null)); // "null"
console.log(String(undefined)); // "undefined"
console.log((123).toString()); // "123"
转为数字
// Number():严格转换,失败返回 NaN
console.log(Number("123")); // 123
console.log(Number("123.45")); // 123.45
console.log(Number("abc")); // NaN(转换失败)
console.log(Number("")); // 0(空字符串 → 0)
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// parseInt():解析整数,遇到非数字就停
console.log(parseInt("123abc")); // 123
console.log(parseInt("abc123")); // NaN(开头不是数字)
console.log(parseInt("3.14")); // 3(只取整数部分)
// parseFloat():解析浮点数
console.log(parseFloat("3.14")); // 3.14
console.log(parseFloat("3.14.15")); // 3.14(遇到第二个小数点就停)
转为布尔
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean("hello")); // true
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
二、隐式类型转换
隐式转换 = JS 引擎在你不知情的情况下自动转换类型。这是很多 bug 的来源。
字符串拼接 → 转字符串
console.log("5" + 3); // "53"(数字 3 被转为字符串)
console.log("温度:" + 65); // "温度:65"
console.log(1 + "2" + 3); // "123"(从左到右,1+"2"→"12","12"+3→"123")
算术运算 → 转数字
console.log("5" - 3); // 2(字符串 "5" 被转为数字)
console.log("6" * "2"); // 12
console.log("10" / "2"); // 5
console.log("hello" - 1); // NaN("hello" 无法转为数字)
逻辑判断 → 转布尔
if ("hello") { // 非空字符串 → true
console.log("执行了");
}
if (0) { // 0 → false
console.log("不会执行");
}
三、Falsy 值:6 个"假"值
只有以下 6 个值转为布尔是 false,其余全部是 true:
容易搞错的 Truthy 值:
console.log(Boolean(" ")); // true(空格字符串 ≠ 空字符串)
console.log(Boolean([])); // true(空数组)
console.log(Boolean({})); // true(空对象)
console.log(Boolean("0")); // true(字符串 "0" ≠ 数字 0)
console.log(Boolean("false")); // true(非空字符串)
记忆口诀:“0 空 null 假 NaN undefined” —— 6 个 falsy,其余全 truthy。
四、== 与 === 的区别
这是 JS 面试必考题,也是日常开发中最容易踩坑的地方。
== 宽松相等(会做类型转换)
console.log(5 == "5"); // true("5" 转成 5)
console.log(0 == false); // true(false 转成 0)
console.log("" == false); // true(都转成 0)
console.log(null == undefined); // true(特殊规则)
console.log([1] == 1); // true([1] 转成 "1" 再转成 1)
=== 严格相等(不做类型转换)
console.log(5 === "5"); // false(类型不同)
console.log(0 === false); // false(类型不同)
console.log("" === false); // false(类型不同)
console.log(null === undefined); // false(类型不同)
一句话总结
== 先转换类型,再比较值 → 不可预测,容易出 bug
=== 不转换类型,直接比较 → 可预测,推荐使用
规则:永远用 ===,除非你明确知道自己在做什么
NaN 的特殊性
console.log(NaN === NaN); // false!NaN 不等于任何值,包括自己
// 判断 NaN 用 isNaN() 或 Number.isNaN()
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true(ES6,更严格)
五、比较运算符
console.log(5 > 3); // true
console.log(5 >= 5); // true
console.log(3 < 5); // true
console.log(5 <= 5); // true
console.log(5 !== "5"); // true(严格不等于)
console.log(5 != "5"); // false(宽松不等于,会做类型转换)
六、逻辑运算符与短路求值
基本用法
// && 与(两边都为 true 才为 true)
console.log(true && true); // true
console.log(true && false); // false
console.log(5 > 3 && 2 < 4); // true
// || 或(任意一边为 true 就为 true)
console.log(true || false); // true
console.log(false || false); // false
// ! 非(取反)
console.log(!true); // false
console.log(!(5 > 3)); // false
console.log(!!"hello"); // true(双重否定 → 转布尔)
console.log(!!""); // false
短路求值(重要!)
// &&:左边为 false,右边不执行
false && console.log("不会执行");
0 && console.log("也不会执行");
// ||:左边为 true,右边不执行
true || console.log("不会执行");
"hello" || console.log("也不会执行");
// 实战用法:设置默认值
var deviceName = userInput || "默认设备名";
// 如果 userInput 是 falsy,就取 "默认设备名"
// 实战用法:安全访问
var result = obj && obj.data && obj.data.value;
// 如果 obj 或 obj.data 不存在,不会报错,返回 undefined
七、动手练:运算符 15 题
// 1. "10" + 20 的结果?为什么?
// 2. "10" - 5 的结果?为什么?
// 3. 0 == false 和 0 === false 的结果?
// 4. null == undefined 和 null === undefined 的结果?
// 5. typeof NaN 的结果?
// 6. NaN === NaN 的结果?
// 7. 写出以下值的 Boolean() 结果:0, "", " ", [], {}, null, undefined, NaN
// 8. "5" * "3" 和 "5" + "3" 的结果?
// 9. !!"hello" 和 !!"" 的结果?
// 10. 变量 temp = 85,写表达式判断 temp 是否在 60-80 之间
// 11. 用 || 给变量设置默认值
// 12. 3 > 2 > 1 的结果?(提示:从左到右执行)
// 13. Number("123abc")、Number("")、Number(" ")、Number(null)、Number(undefined)
// 14. parseInt("3.14") 和 parseFloat("3.14") 的结果?
// 15. 写表达式:温度(temp)大于80 且 状态(status)是"运行中"
八、常见坑点与最佳实践
坑点 1:+ 运算符的二义性
// 加法有两个含义:数字相加 和 字符串拼接
// 只要有一个操作数是字符串,+ 就是拼接
console.log(1 + 2 + "3"); // "33"(先 1+2=3,再 "3"+"3"="33")
console.log("1" + 2 + 3); // "123"(先 "1"+2="12",再 "12"+3="123")
坑点 2:== 的隐式转换链
console.log(false == "0"); // true
console.log(false == 0); // true
console.log("" == 0); // true
// 这就是为什么永远用 === !
坑点 3:typeof 的局限性
console.log(typeof null); // "object" ← bug
console.log(typeof [1, 2, 3]); // "object" ← 无法区分数组和对象
console.log(typeof NaN); // "number" ← NaN 是 number 类型
最佳实践
// 1. 永远用 === 和 !==,不用 == 和 !=
// 2. 判断 NaN 用 isNaN() 或 Number.isNaN()
// 3. 判断数组用 Array.isArray()
// 4. 变量赋值前做类型检查
// 5. 用 !! 快速转布尔
九、总结
🎯 类型转换和比较是 JS 最容易出 bug 的地方。记住铁律:永远用 ===,显式转换代替隐式转换。下周进入流程控制:if/else 和循环。