首页
/ 深入理解 freeCodeCamp Basic JavaScript 课程中的 `++` 自增运算符

深入理解 freeCodeCamp Basic JavaScript 课程中的 `++` 自增运算符

2026-09-07 20:03:48作者:伍希望

在 freeCodeCamp 的 JavaScript 基础课程(Basic JavaScript)中,自增运算符 ++ 是早期引入的高频语法糖之一。本文以课程挑战 56533eb9ac21ba0edf2244ac.md(Increment a Number with JavaScript) 为骨架,完整讲解 ++ 运算符的语法、语义、等价写法、常见陷阱,并结合挑战内部的断言代码说明在线评测是如何自动验收的。读完本文,你既能一次性通过这道挑战,也能透彻理解自增运算在后续循环、计数场景中的应用基础。

挑战在课程体系中的位置

该挑战位于 basic-javascript 课程块中。从课程结构定义 curriculum/structure/blocks/basic-javascript.json(第 63–65 行)可以看到它的登记记录,它的前后课程安排是:

  • 紧邻其前的几课:Add Two Numbers with JavaScriptSubtract One Number from Another with JavaScriptMultiply Two Numbers with JavaScriptDivide One Number by Another with JavaScript
  • 紧邻其后的几课:Decrement a Number with JavaScriptCreate Decimal Numbers with JavaScriptCompound Assignment With Augmented Addition(复合赋值 +=)等。

也就是说,freeCodeCamp 的教学设计遵循"基本算术运算符 → 自增/自减运算符 → 复合赋值运算符"的递进节奏。掌握本课的 ++,正是理解下一课 -- 与再之后 += / -= 等复合赋值的先导。每节课使用唯一的 id(本课为 56533eb9ac21ba0edf2244ac)与全局注册关联,挑战源码 Markdown 的 frontmatter 中也声明了 titlechallengeType: 1forumTopicIddashedName 等元数据。

++ 运算符的核心语义

You can easily increment or add one to a variable with the ++ operator.

**自增(increment)**指把变量的值增加 1。++ 是最简洁的写法。原文档给出了二者完全等价的对照:

i++;

等价于:

i = i + 1;

为什么不再需要等号

i = i + 1 是一种"自引用赋值":先读取 i 的当前值,加 1,再把结果写回 i++ 把这一整套"读-加-写回"操作压缩成了一个后置运算符,因此整行只写 i++; 即可,无需再写等号——这也是本课 Note 强调的重点("eliminating the need for the equal sign")。代码从 10 行可见的冗余写法收缩为 2 个符号,可读性与输入效率同时提升。

后置形式与前置形式

在 JavaScript 语言规范中,++ 存在两种形式,本课使用的是后置形式 i++(先返回旧值,再完成加 1 的副作用):

let i = 87;
const oldValue = i++; // oldValue 为 87,之后 i 变为 88

对应的前置形式 ++i 会先把值加 1 再返回新值:

let i = 87;
const newValue = ++i; // i 先变为 88,newValue 为 88

如果只是单独一行使用(既不接收返回值,也不参与表达式运算),i++;++i; 效果完全相同,这也是本挑战只要求改写 myVar = myVar + 1;myVar++; 的原因。二者的差异要到后续课程涉及复合表达式与循环控制时才需要严格区分。

递减运算符 -- 的对称关系

了解自增之后顺带认识它的"孪生兄弟"很自然:课程紧接安排了姊妹挑战 Decrement a Number with JavaScript(56533eb9ac21ba0edf2244ad.md),其中定义:

i--;

等价于:

i = i - 1;

-- 是自减(decrement),语义完全对称,同样消除了等号。两道挑战并置学习,可以更牢固地建立"运算符简化重复赋值"的直觉。另一个值得留意的衔接点是之后的 Compound Assignment With Augmented Addition(复合赋值 +=):i += 1; 同样是 i = i + 1; 的另一种压缩写法。也就是说 i = i + 1i++i += 1 三者在"把值加一"这一结果上是相通的,区别只在于书写习惯与求值细节(++ 永远只加 1,且与运算符相关的返回值行为不同)。freeCodeCamp 通过多个相邻小挑战,正是为了让学习者从不同角度反复巩固这一语法家族。

动手完成挑战

本课的 --instructions-- 要求:Change the code to use the ++ operator on myVar.

--seed-- 给出的初始代码为:

let myVar = 87;

// Only change code below this line
myVar = myVar + 1;

这里 let 声明了一个可重新赋值的变量 myVar,初值 87(let 声明方式本身是前几课的铺垫内容)。任务要求把指定注释下方的赋值行改写为使用 ++ 运算符,最标准的解法是:

let myVar = 87;

// Only change code below this line
myVar++;

也可以写前置形式:

myVar = 88;

不行——这不是自增写法,而且会被测试拦截(见下文第 4 条断言)。官方 --solutions-- 中的最终答案即为上例 let myVar = 87; + myVar++; 两行。

如何自行验证结果

改写完成后,最终 myVar 的值应为 88。若在 Node.js 或浏览器控制台逐行执行,console.log(myVar) 会输出 88,即 87 + 1 的结果,说明自增副作用已正确写入变量。

自动化测试如何判定"你答对了"

与许多只讲语法的教程不同,freeCodeCamp 的每个挑战都内置了 --hints--(断言列表)。逐个拆解本课 4 条断言,可以清楚看到平台到底在检查什么:

  1. 结果正确性
assert(myVar === 88);

直接执行用户代码后校验 myVar 严格等于 88。这保证最终值正确,但单靠它无法区分答案是否"钻空子"(比如直接 myVar = 88)。

  1. 禁用赋值运算符
assert(
  /let\s+myVar\s*=\s*87;\s*\/*.*\s*([+]{2}\s*myVar|myVar\s*[+]{2})/.test(__helpers.removeJSComments(code))
);

这条正则要求代码中保留 let myVar = 87; 的声明,且后续必须出现 ++myVarmyVar++ 形式,从而排除掉 myVar = 88 之类的硬编码答案。

  1. 必须使用 ++ 运算符
assert(/[+]{2}\s*myVar|myVar\s*[+]{2}/.test(__helpers.removeJSComments(code)));

同理要求源码文本里真实存在自增运算符对 myVar 的运算,防止用 myVar = myVar + 1 这类"没改到点子上"的提交蒙混过关。可以看到,测试对源码文本进行的是正则匹配,[+]{2} 即字符类中出现两个连续的 +

  1. 不得改动指定注释上方的代码
assert(/let myVar = 87;/.test(__helpers.removeJSComments(code)));

用于确认初始声明仍原样存在。

__helpers.removeJSComments 的作用

所有断言都先经过 __helpers.removeJSComments(code) 处理:把用户提交代码中的注释剔除后再做匹配。这样设计的原因很直接——防止学习者把目标代码写进注释来骗过文本匹配(例如写上 // myVar++,此时正则命中了文本但实际并不会执行任何自增)。removeJSComments 是 freeCodeCamp 课程评测环境中广泛使用的公共测试辅助函数,在仓库众多挑战(例如 basic-javascriptdebugginges6regular-expressions 各块的断言里)都能看到同一套调用模式。剔除注释只发生在测试层面,不影响用户在编辑器里保留自己的注释说明。

这一"seed 代码 + 指令 + 断言 + 解决方案"的四段式结构,正是 freeCodeCamp 挑战型 Markdown 的标准格式,它让题目可以被统一解析、渲染与评测。

从本课延伸:自增运算符的实战场景

掌握了 myVar++ 之后,最常见的实战落点有两类:

  • 循环计数器for 循环的更新子句几乎总能看到 i++

    for (let i = 0; i < 10; i++) {
      console.log(i);
    }
    
  • 累加计数:统计发生次数时逐次 +1:

    let clickCount = 0;
    // 每次点击
    clickCount++;
    

需要留意的语言级细节还包括:++ 会把操作数先隐式转为数值再做加法,例如 let s = "5"; s++; 之后 s 变成数字 6;而对 NaNundefined 等无法转成有效数值的操作数,结果会是 NaN。这些边界行为属于 ECMAScript 语言规范层面的通用事实,freeCodeCamp 的后续课程(循环、复合赋值等)会逐步展开,本挑战只需先把"i++i = i + 1"这一等价关系内化即可。

小结

本课虽短,却承载了三个值得记住的要点:

  1. 语法层面i++i = i + 1 的简洁等价物,写自增不再需要等号;
  2. 评测层面:断言由"结果校验 + 源码正则匹配(剔除注释后)"共同构成,既要算对,也要用对运算符;
  3. 知识衔接层面:它与 -- 自减、+= 复合赋值同属"简化重复赋值"的语法家族,与后续课程环环相扣。

想亲手再看一遍原始题面、初始代码与官方解法,直接阅读 56533eb9ac21ba0edf2244ac.md,并在下一课 56533eb9ac21ba0edf2244ad.md 中完成 -- 自减的同类练习即可巩固这套知识。

登录后查看全文
热门项目推荐
相关项目推荐