- 教程
【免费下载链接】jstips
This is about useful JS tips!
本篇技术指南以 jstips 项目第 35 号 tip(Assignment Operators)为骨架,系统讲解 JavaScript 中各类赋值简写(compound assignment)、++/--前置与后置差异、三元运算符替代 if-else、||默认值赋值、数组与对象字面量声明等实战技巧。读完本文,你将掌握一套"打字更少、语义更清晰"的赋值写法,并理解每种简写背后的求值顺序与陷阱,可直接应用于日常业务代码与代码评审。
为什么要写赋值简写
赋值(Assignment)是 JavaScript 中出现频率最高的操作之一。正如该 tip 作者 hsleonis 所说:对于"懒惰的程序员"而言,反复敲击冗长的赋值语句非常耗时,而使用简写可以让代码更干净(cleaner)也更简单(simpler)。这类技巧不是炫技,而是通过减少重复、收敛意图,让代码在可读性与可维护性上同时受益。
复合赋值运算符:一张表掌握所有简写
所谓复合赋值(compound assignment),就是把"二元运算 + 赋值"合并成一个运算符。原文档给出了最核心的一组对照,它们语义完全等价于展开写法:
x += 23; // x = x + 23; y -= 15; // y = y - 15; z *= 10; // z = z * 10; k /= 7; // k = k / 7; p %= 3; // p = p % 3; d **= 2; // d = d ** 2; m >>= 2; // m = m >> 2; n <<= 2; // n = n << 2; n++; // n = n + 1; n--; // n = n - 1;各运算符的语义与适用范围整理如下:
| 简写 | 等价展开 | 运算类型 | 典型使用场景 |
|---|---|---|---|
+= | x = x + y | 加法/字符串拼接 | 累加器、统计计数、字符串累积 |
-= | x = x - y | 减法 | 倒计时、步进回退 |
*= | x = x * y | 乘法 | 缩放、倍增 |
/= | x = x / y | 除法 | 均分、比例计算 |
%= | x = x % y | 取模 | 环形索引、奇偶判断 |
**= | x = x ** y | 幂运算(ES2016) | 几何增长、单位换算 |
>>= | x = x >> y | 有符号右移 | 位运算、二分查找中位 |
<<= | x = x << y | 左移 | 位掩码、快速乘 2 的幂 |
其中**=(指数赋值)是 ES2016 才引入的运算符,使用时需注意运行环境支持情况(Node.js 7+ 与主流现代浏览器均已支持)。>>=与<<=属于位运算范畴,处理的是 32 位整数语义,业务代码中相对少见,但作为 JS 基础语法值得掌握。
以 Node.js v18 实测验证(与文档示例一致):
var x = 2; x += 23; console.log(x); // 25 var p = 7; p %= 3; console.log(p); // 1 var d = 5; d **= 2; console.log(d); // 25 var m = 8; m >>= 2; console.log(m); // 2 var n = 1; n <<= 2; console.log(n); // 4++与--:前缀与后缀的本质差异
++是文档专门强调的"特殊运算符",难点在于它既返回值又改变变量。关键差异是求值的先后顺序:
后缀(postfix):先返回,后自增
var a = 2; var b = a++; // 现在 a 是 3,b 是 2a++语句实际完成两个步骤:
- 返回
a的当前值; - 将
a自增 1。
因此赋值给b的是自增之前的旧值 2,而a本身变为 3。
前缀(prefix):先自增,后返回
var a = 2; var b = ++a; // 现在 a 和 b 都是 3操作符放在变量前面(++a)时,会先完成自增,再把新值 3 返回并赋给b。
--与++行为完全对称,只是把"自增 1"换成"自减 1"。
实践建议:当自增/自减作为独立语句(如i++单独一行)使用时,前缀与后缀没有区别;一旦参与赋值或表达式求值,就必须明确区分。在for循环、数组遍历等场景中,这往往是隐蔽 bug 的来源,建议在代码评审中重点检查。
用三元运算符压缩 if-else 赋值
日常最常见的赋值分支写法:
var newValue; if (value > 10) newValue = 5; else newValue = 2;用三元运算符可以压缩为一行,且语义完全等价:
var newValue = (value > 10) ? 5 : 2;三元运算符的求值规则为:条件 ? 条件为真时的值 : 条件为假时的值。它适合两个分支都只产生一个值的简单场景,能消除临时变量的声明与分支噪声。但需要提醒:当分支内部含有副作用(多次调用、赋值多个变量)或逻辑复杂时,应保留 if-else 以保证可读性——简写的目标是"清晰",而不是"最短"。
||简写:一行完成 null/undefined/空值检查
原文档给出了一个非常典型的赋值场景:
if (variable1 !== null || variable1 !== undefined || variable1 !== '') { var variable2 = variable1; }简写形式:
var variable2 = variable1 || '';其底层原理正是短路求值(short-circuit evaluation):当||左侧的操作数能够决定整个表达式的结果时,右侧根本不会被求值。更精确地说,||返回的是第一个真值(truthy)操作数;如果左侧为假值(falsy),则返回右侧操作数。因此variable1 || ''的含义是:variable1为真值时取variable1本身,否则回退到空字符串。关于该机制的完整讲解可参考仓库姊妹篇 Short circuit evaluation in JS,其中还展示了name = name || 'Bar'式的默认参数写法。
这条简写非常实用,但有一个重要边界条件,文档末尾的 P.S. 专门提醒:如果variable1是数字,必须先检查它是否为 0。因为0在 JavaScript 中是假值,0 || ''会得到''而非0,从而破坏原本"保留数值 0"的意图。
要彻底理解这一点,需要掌握 JavaScript 的假值集合:false、0、-0、0n、''、null、undefined、NaN。仓库中的 Converting truthy/falsy values to boolean(!!技巧)和 Differences between undefined and null 对这部分有专门展开。
实测验证:
var variable1 = ''; // 空字符串是假值 var variable2 = variable1 || ''; console.log(variable2); // "" var variable3 = null; console.log(variable3 || 'fallback'); // "fallback" var count = 0; console.log(count || 10); // 10 —— 注意:0 被当作"未提供"处理了数组字面量:告别new Array()逐项填充
文档对比了两种创建并填充数组的写法。不推荐:
var a = new Array(); a[0] = "myString1"; a[1] = "myString2";推荐使用数组字面量,一行声明 + 初始化:
var a = ["myString1", "myString2"];数组字面量[...]的优势:无需构造器调用、天然支持任意长度与嵌套、可读性更强,且避免了new Array(3)这类"传入单个数字会创建稀疏数组"的经典陷阱。
关联数组:用对象字面量替代字符串索引
JavaScript 中并不存在真正的"关联数组",用数组配合字符串键是反模式:
var skillSet = new Array(); skillSet['Document language'] = 'HTML5'; skillSet['Styling language'] = 'CSS3';正确做法是直接使用对象字面量:
var skillSet = { 'Document language': 'HTML5', 'Styling language': 'CSS3' };二者的本质区别:数组的索引应当是数字;用字符串索引给数组赋值,实际是在给数组对象动态添加属性,并不会像真正的关联容器那样工作。对象字面量才是"键-值映射"的正确载体,这也与仓库中 Check if a property is in a Object 讨论的in运算符与hasOwnProperty检查互为呼应。
综合实践清单
把本文所有简写整合进一段可运行的示例,便于对照复习:
// 1. 复合赋值 var score = 0; score += 10; // 10 score -= 2; // 8 // 2. 前缀/后缀自增 var i = 0; var j = i++; // j = 0, i = 1 var k = ++i; // k = 2, i = 2 // 3. 三元赋值 var level = (score > 5) ? 'high' : 'low'; // 'high' // 4. || 默认值(注意 0 与 '' 的边界) var userInput = ''; var finalInput = userInput || 'default'; // 'default' // 5. 数组与对象字面量 var tags = ['js', 'tips']; var config = { debug: true, retries: 3 };延伸阅读
- 本文依据:Assignment Operators(jstips 第 35 期),仓库内另有简体中文版 _posts/zh_CN/javascript/2016-02-04-assignment-shorthands.md、西班牙语版 _posts/es_ES/javascript/2016-02-04-assignment-shorthands.md 与繁体中文版 _posts/zh_TW/javascript/2016-02-04-assignment-shorthands.md;
- Short circuit evaluation in JS:
||与&&短路求值的完整原理与默认参数实践; - Converting truthy/falsy values to boolean:
!!双非运算符与真假值速查; - Differences between undefined and null:
null与undefined的判定差异,辅助理解||回退逻辑; - Basics declarations:
var声明与链式赋值x = y = 1的作用域细节。
以上代码示例均在 Node.js v18 环境下实际运行验证,结论与文档描述一致。需要注意的是:本文示例沿用原文档的var写法以忠实还原 2016 年语境,现代项目中建议按需升级为let/const(可参考仓库 ES6, var vs let),但运算符本身的求值语义完全不变。
- 教程
【免费下载链接】jstips
This is about useful JS tips!
相关推荐
3大技术突破:ElasticFusion如何实现实时密集视觉SLAM的革命性创新
3大技术突破:ElasticFusion如何实现实时密集视觉SLAM的革命性创新 在机器人导航、增强现实和三维重建领域,实时密集视觉SLAM技术一直是研究的热点
计算机视觉Imba 运算符完全指南:从算术、逻辑到位运算与赋值技巧
Imba 运算符完全指南:从算术、逻辑到位运算与赋值技巧 本篇指南以 Imba 官方文档( operators.md https://link.gitcode.
编程语言编译器语言运行时cppcheck 的 operatorEqVarError 检查:如何检测手写赋值运算符遗漏成员赋值
cppcheck 的 operatorEqVarError 检查:如何检测手写赋值运算符遗漏成员赋值 本指南围绕 cppcheck 静态分析器中的 operat
开发工具静态分析代码质量质量保障
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考