// 03 · 运算符 // 学练复习一体:概念总结 → 示范 → 轮到你 // 跑法:Quokka / 右上角 ▷ / node 本文件 // 示范区每行后注释是【预期输出】,跑完自己对答案 // ═════ 概念总结 ═════ // // 1. 算术运算符 // ┌──────┬────────────┬──────────┬──────────────────────────┐ // │ 符号 │ 含义 │ 例子 │ 结果 │ // ├──────┼────────────┼──────────┼──────────────────────────┤ // │ + │ 加 │ 2 + 3 │ 5 │ // │ - │ 减 │ 5 - 2 │ 3 │ // │ * │ 乘 │ 4 * 3 │ 12 │ // │ / │ 除 │ 10 / 4 │ 2.5(JS 除法不取整!) │ // │ % │ 取余(模) │ 10 % 3 │ 1 │ // │ ** │ 幂(次方) │ 2 ** 3 │ 8 │ // └──────┴────────────┴──────────┴──────────────────────────┘ // 两个初学重点: // - JS 里 10 / 4 = 2.5,不像有些语言整数相除会取整。 // - % 取余超常用:判断奇偶(n % 2 === 0 就是偶数)、循环里做周期。 // // ⚠️ 负数取余的坑:判奇偶要用 === 0 不要用 === 1 // JS 里取余结果的符号跟着"被除数"走,负数取余是负的: // 7 % 2 // 1 -7 % 2 // -1 ← 不是 1!符号跟着 -7 // 所以判奇偶: // n % 2 === 0 // ✅ 判偶数,对正负数都成立 // n % 2 === 1 // ❌ 判奇数,遇负数会漏:-7%2 是 -1,=== 1 得 false → 误判成偶数 // 结论:判奇偶一律用 n % 2 === 0(判偶),再用 else 处理奇数。别用 === 1。 // // 2. 赋值运算符 // = 是"赋值"(把右边存进左边),下面是简写: // ┌────────┬──────────────┬────────┐ // │ 写法 │ 等价于 │ 说明 │ // ├────────┼──────────────┼────────┤ // │ x += 5 │ x = x + 5 │ 加等于 │ // │ x -= 5 │ x = x - 5 │ 减等于 │ // │ x *= 2 │ x = x * 2 │ 乘等于 │ // │ x /= 2 │ x = x / 2 │ 除等于 │ // └────────┴──────────────┴────────┘ // // 3. 比较运算符 → 结果是布尔值 ⭐ // ┌───────────────┬──────────────────────────────┬──────────┬──────────┐ // │ 符号 │ 含义 │ 例子 │ 结果 │ // ├───────────────┼──────────────────────────────┼──────────┼──────────┤ // │ > < >= <= │ 大小比较 │ 5 > 3 │ true │ // │ === │ 严格等于(值和类型都要相等) │ 1 === 1 │ true │ // │ !== │ 严格不等 │ 1 !== 2 │ true │ // │ == │ 松散等于(会偷偷转类型) │ 1 == '1' │ true ⚠️ │ // └───────────────┴──────────────────────────────┴──────────┴──────────┘ // ⭐⭐ 最重要的一条规则:永远用 ===,别用 == // == 会做"隐式类型转换",制造诡异结果: // 1 == '1' // true ← 数字 1 和字符串 '1' 被判相等?! // 1 === '1' // false ← === 看类型,数字 ≠ 字符串,正确 // 0 == '' // true ← 更离谱 // 记死这条:比较一律用 === 和 !==。这是 JS 最著名的坑之一。 // // 4. 逻辑运算符 // ┌──────┬───────────┬──────────────────┐ // │ 符号 │ 含义 │ 口诀 │ // ├──────┼───────────┼──────────────────┤ // │ && │ 与(AND) │ 都为真才真 │ // │ || │ 或(OR) │ 有一个真就真 │ // │ ! │ 非(NOT) │ 真假反转 │ // └──────┴───────────┴──────────────────┘ // true && false // false true || false // true !true // false // 常用于条件判断:age >= 18 && hasTicket(成年且有票)。 // // 5. 一个坑:+ 对字符串是"拼接" ⭐ // 1 + 2 // 3 ← 数字相加 // '1' + '2' // '12' ← 字符串拼接 // '1' + 2 // '12' ← 只要有一个是字符串,就拼接! // 1 + '2' + 3 // '123' ← 从左到右,一旦变字符串后面全拼 // 其他运算符(- * /)不会拼接,反而会把字符串转成数字再算: // '6' - 2 === 4、'6' * 2 === 12。只有 + 特殊。 // // 6. 类型转换:显式 vs 隐式 ⭐⭐ // 上面这些坑的根源,都是 JS 在偷偷"转类型"。 // 隐式转换(JS 自作主张,坑的来源)—— 你没让它转,它自己转了: // '5' + 3 // '53' ← 偷偷把 3 转成字符串,拼接 // '5' - 3 // 2 ← 偷偷把 '5' 转成数字 // 0 == '' // true ← 偷偷都转成数字比较 // 'abc' - 1 // NaN ← 转不成数字 → NaN(会像病毒一样传染后续计算) // 显式转换(你主动写,推荐 ✅)—— 意图清楚、无意外: // Number('42') // 42 Number('abc') // NaN ← 转不了就是 NaN // parseInt('42px')// 42 parseFloat('3.14') // 3.14 // String(42) // '42' // Boolean('') // false Boolean('hi') // true Boolean(0) // false // 方向性差异(记住): // - 数字 → 字符串:几乎总能成功 // - 字符串 → 数字:可能失败,失败得 NaN(处理用户输入时要留心) // 原则:能用显式(Number()/String())就别靠隐式。 // // 7. TypeScript 能克服这些坑吗?—— 部分能 ⭐ // TS 在写代码时(编译期)检查类型,能挡一大类,但不是全部: // ┌──────────────────────────────────────────────┬───────────────┐ // │ 坑 │ TS 能挡吗 │ // ├──────────────────────────────────────────────┼───────────────┤ // │ '5' - 3(类型不匹配的运算) │ ✅ 编译期报错 │ // │ 0 == ''(乱比较) │ ✅ 报错 │ // │ '5' + 3(拼接,语法合法) │ ❌ 不管 │ // │ 外部数据(输入/请求/JSON.parse)类型错 │ ❌ 只信标注 │ // │ 运行时才暴露的问题 │ ❌ 类型已消失 │ // └──────────────────────────────────────────────┴───────────────┘ // 心智模型:TS 是"写代码时的第一道墙",挡掉大部分手滑;但 + 拼接、外部数据 // 这些盲区,仍要靠显式转换 + 校验输入兜底。理解 JS 转换原理,是用好 TS 的前提。 // // ✅ 本主题要点回顾 // 1. 算术:/ 不取整、% 取余判奇偶、** 次方 // 2. 赋值简写:+= -= *= /= // 3. 比较永远用 === / !==,别用 == ⭐⭐ // 4. 逻辑:&&(都真)、||(有一真)、!(反转) // 5. + 遇字符串会拼接,其他运算符会转数字 ⭐ // 6. 能用显式转换(Number()/String())就别靠隐式 ⭐ // 7. TS 能挡"类型不匹配"的坑,但挡不住 + 拼接和外部数据 —— 显式转换的习惯不能丢 // ═════ 示范 ═════ // ── 1. 算术运算符 ───────────────────────────────── console.log(2 + 3) // 5 console.log(5 - 2) // 3 console.log(4 * 3) // 12 console.log(10 / 4) // 2.5 ← JS 除法不取整! console.log(10 % 3) // 1 ← 取余 console.log(2 ** 3) // 8 ← 2 的 3 次方 // ── 2. % 取余判断奇偶 ⭐ ────────────────────────── console.log(10 % 2) // 0 ← 余 0 → 偶数 console.log(7 % 2) // 1 ← 余 1 → 奇数 console.log(10 % 2 === 0) // true ← 判断偶数的标准写法 // ── 3. 赋值简写 ─────────────────────────────────── let x = 10 x += 5 // 等价 x = x + 5 console.log(x) // 15 x *= 2 // 等价 x = x * 2 console.log(x) // 30 // ── 4. 比较运算符 → 布尔值 ──────────────────────── console.log(5 > 3) // true console.log(5 <= 4) // false console.log(1 === 1) // true console.log(1 !== 2) // true // ── 5. === vs == 的坑 ⭐⭐(最重要)──────────────── console.log(1 === '1') // false ← 严格:类型不同 → 不等(正确做法) console.log(1 == '1') // true ← 松散:偷偷转类型 → 相等(危险!) console.log(0 == '') // true ← == 的离谱行为 // 结论:永远用 ===,别用 == // ── 6. 逻辑运算符 ───────────────────────────────── console.log(true && false) // false ← 都真才真 console.log(true || false) // true ← 有一真就真 console.log(!true) // false ← 反转 const age = 20 const hasTicket = true console.log(age >= 18 && hasTicket) // true ← 成年且有票 // ── 7. + 遇字符串会拼接 ⭐ ──────────────────────── console.log(1 + 2) // 3 ← 数字相加 console.log('1' + '2') // '12' ← 字符串拼接 console.log('1' + 2) // '12' ← 有一个字符串就拼接 console.log(1 + '2' + 3) // '123' ← 从左到右,变字符串后全拼 // 其他运算符反而会把字符串转成数字: console.log('6' - 2) // 4 ← - 让 '6' 变数字 6 console.log('6' * 2) // 12 ← * 同理 // ═════ 轮到你 ═════ // 👇 轮到你(把 ??? 换掉,取消注释,跑一下对答案) // 练习 A:判断 15 是不是偶数(用 % 和 ===),应打印 false // console.log(15 % 2 === 0) // 练习 B:一个人 age = 16,判断"成年 且 有票",应打印 false // const myAge = ??? // const ticket = true // console.log(??? >= 18 && ticket) // 练习 C:猜一下 '5' + 3 和 '5' - 3 分别是什么?先猜再取消注释验证 // console.log('5' + 3) // 你猜:___ // console.log('5' - 3) // 你猜:___ // 练习 A:判断 15 是不是偶数 → 要用 === 才是"判断" console.log(15 % 2 === 0) // false ← 15%2 是 1,1===0 为 false console.log(15 % 2) // 1 ← 对比:这只是算余数,不是判断 // 练习 B:age=16,判断"成年(>=18)且有票" const myAge = 16 const ticket = true console.log(myAge >= 18 && ticket) // false ← 16 不够 18,&& 整体为 false // 练习 C:先猜后验(你猜的 '53' 和 2 都对!) console.log('5' + 3) // '53' ← + 遇字符串 → 拼接 console.log('5' - 3) // 2 ← - 把 '5' 转成数字 → 5-3