JavaScript学习笔记:6.表达式和运算符
上一篇搞定了函数这个“代码复用神器”,这一篇咱们来拆解JS的“底层操作核心”——表达式和运算符。如果说变量是零散的“乐高积木”,函数是预制的“复杂组件”,那表达式就是拼好的“积木模块”,运算符就是连接它们的“卡扣”——没有它们,代码就是一堆孤立的字符,根本跑不起来。
很多新手栽在==和===的区别上,被a++和++a绕晕,甚至不知道&&还能当“短路开关”用,本质都是没吃透这俩核心概念。今天就用“生活化场景+踩坑实录”的方式,把这些“卡扣”的用法、坑点讲透,让你写代码时又快又稳,还能耍点“优雅技巧”~
一、先理清:表达式和运算符的“爱恨情仇”
先解决最基础的混淆——这俩不是一回事,但天生绑定,缺一不可。
1. 表达式:有“结果”的代码片段
表达式的核心是“能算出一个具体值”,就像“3块积木拼出的小房子”,不管多简单或复杂,最终都有明确产出。
- 简单表达式:
100(值为100)、"前端"(值为“前端”)、user.age(值为user对象的age属性) - 复杂表达式:
10 + 20(值30)、fn(5)(值为函数返回值)、a && b || c(值为逻辑运算结果) - 隐藏表达式:
{ name: "张三" }(值是这个对象)、[1,2,3](值是这个数组)
记住:只要一段代码能跟在console.log()里打印出结果,它就是表达式。
2. 运算符:表达式的“操作工具”
运算符就是用来“操作数据、拼接表达式”的工具,比如“+”“===”“&&”,就像乐高的“卡扣”“连接件”,没有它们,积木拼不成模块。
JS的运算符家族很庞大,但核心常用的就几类:赋值、比较、算术、逻辑、三元、扩展。咱们重点聊这些“高频选手”,冷门的位运算符简单带过,避免信息过载。
二、赋值运算符:给变量“装内容”的正确姿势
赋值运算符的核心是“把右边的值装进左边的变量”,但不只是=这么简单,还有能偷懒的“复合赋值”和高级的“解构赋值”。
1. 基础赋值:别把“赋值”当“比较”
最容易踩的低级坑:在if条件里写=(赋值) instead of ===(比较),相当于“硬给变量改值”,逻辑直接错乱。
// 反面例子:把赋值当比较,永远返回true
let isLogin = false;
if (isLogin = true) { // 这里是赋值,isLogin变成true,条件永远成立
console.log("登录成功"); // 错误执行!
}
// 正面例子:用===做比较
if (isLogin === true) {
console.log("登录成功"); // 正确判断
}
2. 复合赋值:偷懒的“快捷键”
当需要“修改变量后再存回去”时,复合赋值能少写重复代码,比如a = a + 3可以写成a += 3,清爽又高效。
常用复合赋值对照表:
| 运算符 | 等价写法 | 场景示例 |
|---|---|---|
x += y | x = x + y | 数字累加、字符串拼接 |
x -= y | x = x - y | 数字递减 |
x *= y | x = x * y | 倍数计算 |
x /= y | x = x / y | 除法运算 |
x ??= y | x ?? (x = y) | 空值兜底(ES6+) |
坑点提醒:x += y对字符串是拼接,对数字是累加,别混着用:
let str = "奶茶";
str += "加珍珠"; // "奶茶加珍珠"(字符串拼接)
let num = 5;
num += 3; // 8(数字累加)
3. 解构赋值:批量“拆包”的高级操作
这是ES6的“神技”,能从数组或对象里快速提取数据,不用一个个索引/属性访问,代码瞬间简洁。
// 数组解构:提取数组元素
const [a, b, c] = [10, 20, 30];
console.log(a); // 10,b=20,c=30
// 对象解构:提取对象属性
const user = { name: "张三", age: 25 };
const { name, age } = user;
console.log(name); // "张三"
// 实战场景:函数参数解构(超常用)
function printUser({ name, age }) {
console.log(`${name}今年${age}岁`);
}
printUser(user); // "张三今年25岁"
避坑指南:解构时如果变量名和属性名不一致,要指定别名,否则会undefined:
const { name: userName } = user; // 别名userName,对应user.name
console.log(userName); // "张三"
三、比较运算符:判断“对不对”的坑王
比较运算符用来判断两个值的关系(相等、大小等),返回true或false,但==的“自动类型转换”坑了无数人,堪称“JS坑王”。
1. 核心区别:==(模糊比较)vs ===(严格比较)
这是面试必问,也是日常开发最容易出错的点,记住一句话:非特殊场景,一律用===!
==:会先自动转换两个值的类型,再比较“转换后的值”===:不转换类型,直接比较“值+类型”,完全相等才返回true
看看==的离谱转换:
console.log("10" == 10); // true(字符串转数字)
console.log(0 == false); // true(0和false都转成false)
console.log("" == false); // true(空字符串转false)
console.log(null == undefined); // true(特殊规则,互认亲戚)
console.log(NaN == NaN); // false(NaN:我连自己都不认)
而===的判断才是“靠谱的”:
console.log("10" === 10); // false(类型不同:字符串vs数字)
console.log(0 === false); // false(类型不同:数字vs布尔)
console.log(null === undefined); // false(类型不同)
2. 其他比较运算符:注意类型一致性
> < >= <=也会触发类型转换,尤其是字符串比较,会按Unicode编码排序,不是按数字大小:
// 坑点:字符串比较
console.log("2" > "10"); // true("2"的Unicode编码比"1"大)
console.log(Number("2") > Number("10")); // false(转数字后正确比较)
// 正确姿势:先统一类型,再比较
const num1 = "15";
const num2 = 20;
console.log(Number(num1) < num2); // true
四、算术运算符:做计算的“小心机”
算术运算符就是加减乘除(+ - * /),但+有双重身份,++/--有前后置区别,还有NaN和Infinity这两个“捣蛋鬼”。
1. +的双重身份:加法或拼接
+是唯一能同时处理数字和字符串的运算符,规则很简单:只要有一边是字符串,就变成拼接。
console.log(10 + 20); // 30(数字加法)
console.log("10" + 20); // "1020"(字符串拼接)
console.log(10 + "20"); // "1020"(字符串拼接)
console.log(10 + true); // 11(true转成1,数字加法)
实战技巧:用+变量快速转数字(比Number()简洁):
const strNum = "25";
console.log(+strNum); // 25(字符串转数字)
console.log(+"3.14"); // 3.14(字符串转浮点数)
console.log(+true); // 1(布尔转数字)
2. ++/--:先算账还是先给钱?
自增(++)和自减(--)是“变量自增1/减1”的简写,但前后置的返回值完全不同,像“先给钱再算账”和“先算账再给钱”:
- 后置(
a++):先返回a的原值,再让a加1(先给钱,再记账) - 前置(
++a):先让a加1,再返回新值(先记账,再给钱)
代码实测:
let a = 5;
console.log(a++); // 5(先返回5,a变成6)
console.log(a); // 6
let b = 5;
console.log(++b); // 6(先变成6,再返回6)
console.log(b); // 6
// 坑点:复杂表达式中混用
let c = 1;
let d = c++ + ++c; // 拆解:c++返回1(c变2),++c变3返回3 → 1+3=4
console.log(d); // 4
避坑指南:尽量别在表达式里混用++/--,拆成单独语句更易读:
let c = 1;
c++; // 先自增
let d = c + ++c; // 2 + 3 = 5,逻辑清晰
3. 捣蛋鬼:NaN和Infinity
算术运算无法得到有效结果时,就会冒出这俩:
console.log(0 / 0); // NaN(无意义运算)
console.log(10 / 0); // Infinity(正数除以0)
console.log(-10 / 0); // -Infinity(负数除以0)
console.log(NaN + 5); // NaN(NaN和任何数运算都是NaN)
避坑技巧:用Number.isNaN()判断NaN(别用isNaN(),会误判非数字类型):
console.log(Number.isNaN(NaN)); // true(正确)
console.log(Number.isNaN("10")); // false(正确)
console.log(isNaN("10")); // false(还好)
console.log(isNaN("abc")); // true(误判!"abc"是字符串不是NaN)
五、逻辑运算符:不止“与或非”,还能当“开关”
逻辑运算符(&& 与、|| 或、! 非)不仅能做逻辑判断,还能利用“短路特性”简化代码,是JS开发者的“隐藏技巧”。
1. 基础逻辑:真与假的规则
JS中“假值”只有6个:false、0、""、null、undefined、NaN,其他全是“真值”。逻辑运算的核心就是判断这些:
&&:两边都为真,才返回真(一假则假)||:只要有一边为真,就返回真(一真则真)!:取反(真变假,假变真)
2. 核心技巧:短路特性的实用场景
逻辑运算符会“偷懒”——一旦能确定结果,就停止执行后面的代码,这就是“短路”,用好了能少写很多if:
// 1. ||:空值兜底(左边是假值,就用右边的值)
const name = user.name || "匿名用户"; // user.name为空时,用"匿名用户"
// 进阶:用??替代||(只对null/undefined兜底,不误伤0、"")
const age = 0;
console.log(age || 18); // 18(坑:0被当成假值)
console.log(age ?? 18); // 0(正确:只认null/undefined为“空”)
// 2. &&:条件执行(左边是真值,才执行右边的函数)
user && user.login(); // 避免user为null时调用login()报错
// 等价于:if (user) { user.login(); }
// 3. !:快速转布尔值(双重!更稳妥)
const isEmpty = !arr.length; // arr为空时,arr.length是0(假),!0为true
const isTrue = !!arr.length; // 双重!转成标准布尔值,更易读
六、其他常用运算符:实用但容易忽略
除了上面的“高频选手”,还有几个运算符日常用得也多,简单讲清用法和场景:
1. 三元运算符:简化if-else的“快捷键”
唯一需要三个操作数的运算符,语法:条件 ? 真分支 : 假分支,适合“二选一”的简单场景。
// 普通if-else
let statusText;
if (age >= 18) {
statusText = "成年";
} else {
statusText = "未成年";
}
// 三元运算符简化
const statusText = age >= 18 ? "成年" : "未成年";
坑点:别嵌套超过两层!否则代码会变成“天书”:
// 反面例子:嵌套三层,难以理解
const level = score > 90 ? "优秀" : score > 70 ? "良好" : "及格";
// 正面例子:复杂判断用if-else
let level;
if (score > 90) level = "优秀";
else if (score > 70) level = "良好";
else level = "及格";
2. 关系运算符:in和instanceof
in:判断对象/数组是否有某个属性/索引const user = { name: "张三" }; console.log("name" in user); // true(user有name属性) const arr = [1,2,3]; console.log(0 in arr); // true(arr有索引0)instanceof:判断对象是否是某个类型的实例const date = new Date(); console.log(date instanceof Date); // true(date是Date实例) console.log([] instanceof Array); // true(数组是Array实例)
3. 位运算符:简要带过
位运算符(& | ^ ~ << >>)是操作二进制的,日常开发用得少(除非做底层优化、位掩码),知道它们的存在即可,不用深钻,避免精力浪费。
七、表达式进阶:常见类型大盘点
除了上面的运算符组合,JS还有很多常用表达式,核心都是“有返回值”:
- 对象初始化表达式:
{ name: "张三", age: 25 }(返回对象) - 数组初始化表达式:
[1,2,3](返回数组) - 函数调用表达式:
fn(10)(返回函数返回值) - 成员访问表达式:
obj.name、arr[0](返回属性/元素值) - 分组表达式:
(10 + 20) * 3(改变运算符优先级,返回90)
八、核心避坑总结:3个原则少踩90%的坑
- 比较用
===:除了null == undefined(判断空值),其他场景一律用严格比较,拒绝自动类型转换的坑。 - 不确定优先级就加括号:运算符优先级复杂(比如算术>比较>逻辑>赋值),记不住就用
()强制改变顺序,代码更清晰。 - 主动控制类型转换:别依赖JS自动转换,用
Number()、String()、Boolean()手动转,或用+变量快速转数字。
九、结尾:表达式和运算符的“本质”
表达式和运算符是JS的“语法基石”,所有复杂逻辑最终都会拆解成“表达式+运算符”的组合。新手和高手的区别,不在于记住多少运算符,而在于能否避开坑点,用简洁的表达式写出高效逻辑。
JavaScript表达式与运算符详解
811

被折叠的 条评论
为什么被折叠?



