今天,我们不谈那些花里胡哨的框架,沉下心来聊聊JavaScript的基石——运算符。无论你是刚在教程(https://www.ebingou.cn/jiaocheng/)模块入门的新手,还是在编程(https://www.ebingou.cn/biancheng/)路上探索的老朋友,理解运算符都至关重要。很多人在初学时常会忽略它们的深度,导致后期看别人源码时一头雾水。
运算符就是用来操作数据的符号或关键字。它们是构成表达式的基本单元,决定了数据如何被计算、比较和赋值。下面,小编结合自己的编码经验,把这些运算符掰开了揉碎了讲给你听。
算术运算:不止是加减乘除
算术运算符是我们接触最早的一批,但有几个细节值得注意。
-
+(加法):除了做数字相加,还能拼接字符串。但这里有个坑:如果'5' + 3,结果是字符串'53',因为+一见字符串,就把数字也转为字符串做拼接了。 -
-、*、/(减法、乘法、除法):它们会努力把操作数转为数字进行计算。比如'10' - 2,结果是数字8。 -
%(取余 / 求模):这个非常有用来判断奇偶、周期性变化。 -
++和--(递增和递减):分前置和后置。比如let i = 1; let a = i++;,a的值是1,因为先把i的值赋给a,i再加1。而let b = ++i;,b的值是3(假设i经过上一步已经为2),因为i先加1,再赋给b。这个细微差别在循环和特定算法里要格外留心。
个人见解:很多新手在计算复利或累加时,容易混淆++的前后置。我的建议是:单独成行。如果你不是写那种极精简的代码,就把i++或者++i单独写一行,既清晰又不易出错。
赋值与比较:优雅地更新与判断
-
赋值运算符:除了
=,+=、-=这类复合运算符能让代码更简洁。比如count = count + 1可以写成count += 1。在代码号学习源码(https://www.ebingou.cn/yuanma/)时,你会发现高手常用这种写法。 -
比较运算符:关键在于相等与全等。我见过太多因为
==和===引起的bug。-
==:它会做类型转换再比较,比如0 == false结果是true,逻辑上说得通,但程序里往往不是我们想要的。 -
===:它要求值和类型都相等,0 === false结果是false。
-
个人建议:永远使用===和!==。除非你非常清楚自己在做什么(比如判断if (someVar == null)来同时检查null和undefined),否则,一律用严格比较,能让你的代码逻辑更严谨。
逻辑运算与短路求值
逻辑运算符&&(与)、||(或)、!(非)是控制流程的好帮手。但它们的核心机制是“短路求值”。
-
&&:找假值。左边为假,直接返回左边值,不再计算右边;左边为真,返回右边值。 -
||:找真值。左边为真,直接返回左边值,不再计算右边;左边为假,返回右边值。
这个特性常用来设置默认值或安全地调用函数。
// 设置默认值 —— 常用手法
let config = userConfig || { theme: 'default' };
// 安全调用 —— 避免报错
let user = null;
let userName = user && user.name; // 返回 null,而不是报错
位运算与高级操作
位运算符操作的是数字的二进制表示,日常业务逻辑用得少,但在权限控制、状态标记、图形学、性能极致优化的场景里,它们是神器。
-
&(按位与):常用于权限判断。比如我们定义READ = 0b100,WRITE = 0b010,EXECUTE = 0b001,用户的权限userPerm = READ | WRITE(按位或组合),要判断是否有读权限,就用(userPerm & READ) !== 0。 -
|(按位或):用来组合权限。 -
~(按位非):一个实用技巧是~~num可以快速将浮点数转为整数,效果同Math.floor(num),但性能稍好(不过可读性差,我一般不推荐在团队项目里用)。
他实用运算符
-
三元运算符
::它是if-else的简洁版,但嵌套多了可读性极差。我主张只在一层判断时使用,比如let drink = age >= 18 'beer' : 'juice';。 -
可选链
.:ES2020引入的福音。以前访问深层属性要写一长串&&判断(obj && obj.a && obj.a.b),现在直接obj.a.b,如果中间某个环节不存在或为null/undefined,会直接返回undefined,不会报错。 -
空值合并 :和
||类似,但只检查null或undefined。而||检查的是假值(false,0,'',null,undefined等)。比如let count = 0 10,结果是0,因为0不是null/undefined;但let count = 0 || 10,结果是10,因为0是假值。 -
typeof和instanceof:typeof判断基础类型很准,但遇到typeof null结果是object,这是历史遗留问题。instanceof用来检查对象是否属于某个类或派生类。 -
逗号运算符
,:会执行所有表达式,但只返回一个的值。实际开发中很少单独用,但在for循环里常见:for (let i = 0, j = 10; i < j; i++, j--)。
深入一点:优先级与类型转换
写复杂表达式时,运算符优先级是bug的温床。比如a && b || c的运算顺序是怎样的?与记忆那庞大复杂的优先级表,不如直接加括号()。括号能清晰地表达你的意图,也让阅读你代码的人(包括未来的自己)少费些脑筋。
类型转换(Coercion)无处不在。JavaScript是弱类型语言,类型转换既灵活也易出错。比如[] + []结果是空字符串,[] + {}结果是[object Object]。了解这些怪异现象有助于调试,但我更建议你在编码时保持类型一致,避免依赖隐式转换来做核心逻辑。
总结
JavaScript运算符远不止表面的加减乘除。深入理解它们,特别是短路求值、可选链、严格比较等特性,能让你写出更简洁、健壮、易读的代码。下次在代码号(https://www.ebingou.cn/)上阅读优秀源码时,不妨多留意一下这些运算符的用法,相信你会有新的收获。学习编程,就是在这些细节的不断琢磨中进步的。