首页
/ freeCodeCamp 基础 JavaScript 挑战详解:用 `+=` 运算符向字符串追加变量(Appending Variables to Strings)

freeCodeCamp 基础 JavaScript 挑战详解:用 `+=` 运算符向字符串追加变量(Appending Variables to Strings)

2026-09-07 11:41:57作者:伍希望

本篇技术指南围绕 freeCodeCamp 开源课程仓库中 Basic JavaScript(基础 JavaScript)块里的一堂实战挑战课展开——「Appending Variables to Strings(向字符串追加变量)」。你将掌握 += 复合赋值运算符在字符串拼接场景下的完整语义、它与 let/const 声明方式的关系、如何在本课程中完成该挑战并通过全部自动测试,以及这一挑战在 freeCodeCamp 课程文件与校验体系中的真实落地形式。读完即可举一反三地独立解决同系列字符串拼接题目。

课程档案:这堂挑战在仓库中的位置

该挑战的源文件位于 curriculum/challenges/english/blocks/basic-javascript/56533eb9ac21ba0edf2244ed.md,其 Markdown 头部的 frontmatter 记录了它的唯一身份与课程属性:

---
id: 56533eb9ac21ba0edf2244ed
title: Appending Variables to Strings
challengeType: 1
forumTopicId: 16656
dashedName: appending-variables-to-strings
---

其中 challengeType: 1 对应仓库 packages/shared/src/config/challenge-types.ts 中定义的 js 类型(经典 JavaScript 代码挑战):它使用 classic 视图渲染,提交后通过测试断言(tests)来判定是否通过。该挑战与同目录下的另外几篇构成完整的字符串主题递进链路:

整块 Basic JavaScript 的课程顺序与元数据(含 helpCategory: "JavaScript")维护在 curriculum/structure/blocks/basic-javascript.json 中。

先理清三个基本概念:字符串字面量、拼接与追加

文档开篇用 <dfn>literals</dfn>(字面量)定义了操作对象:在源码中直接书写的 "awesome!""freeCodeCamp is " 这类用引号包裹的原始字符串值,就是字符串字面量。

JavaScript 中我们可以像搭积木一样,把多个字符串字面量跨越多行组合成一个新字符串。前导课程展示了两种组合方式:

// 用 + 一次性拼接(参见 Concatenating Strings with Plus Operator)
const ourStr = "I come first. " + "I come second.";
// 用 += 分段累积(参见 Concatenating Strings with the Plus Equals Operator)
let ourStr = "I come first. ";
ourStr += "I come second.";

x += y 本质上是 x = x + y 的简写:先把 x 的当前值与右侧的 y 相加/拼接,再把结果重新赋值给 x。当左右两侧都是字符串时,它执行的是字符串拼接(concatenation)——把右侧内容原样附加到左侧变量现有内容的末尾,因此常用于把一个较长的字符串拆成几行、分步构建。

需要特别注意的是:+= 会改写变量自身的值,所以被追加的变量必须用 let 声明(可变绑定),而不能用 const 声明——给 const 变量重新赋值会在运行时报错。这正解释了前导课程 Concatenating Strings with the Plus Equals Operator 里使用 let ourStr、以及本课使用 let myStr 的原因。

本课核心:把「变量」追加到字符串末尾

前几课拼接的对象都是字符串字面量,本课的语法能力进一步升级——我们也可以把一个变量(例如提前存放在 const anAdjective 中的形容词)通过 += 追加到现有字符串变量之后。

文档给出的官方示例非常精炼:

const anAdjective = "awesome!";
let ourStr = "freeCodeCamp is ";
ourStr += anAdjective;

逐行推演这段代码:

  1. const anAdjective = "awesome!"; 声明一个只读常量,值为字符串 awesome!
  2. let ourStr = "freeCodeCamp is "; 声明一个可变变量,初始值为 freeCodeCamp is (注意末尾带有一个空格);
  3. ourStr += anAdjective; 等价于 ourStr = ourStr + anAdjective;,把 anAdjective 的值 awesome! 原样接到 freeCodeCamp is 之后。

最终 ourStr 的值为:

freeCodeCamp is awesome!

一个需要反复强调的细节:字符串拼接不会自动插入空格。示例中 freeCodeCamp is 之所以能拼出可读的完整句子,是因为初始字符串自身以空格结尾,空格必须由开发者自己维护。

动手任务:Instructions 逐条解读与解题步骤

挑战给出的任务(Instructions)如下:

Set someAdjective to a string of at least 3 characters and append it to myStr using the += operator. (将 someAdjective 设为一个至少 3 个字符的字符串,并用 += 运算符把它追加到 myStr。)

题目初始代码(seed)长这样:

// Change code below this line
const someAdjective = "";
let myStr = "Learning to code is ";

求解分三步走:

第 1 步:给 someAdjective 赋一个至少 3 个字符的字符串。

const someAdjective = "awesome";

注意 "" 空字符串的长度是 0,直接提交不会通过第一条测试;赋值任何 3 个或以上字符(可含空格)的内容均可。

第 2 步:使用 +=someAdjective 追加到 myStr

myStr += someAdjective;

myStr 的初始值 "Learning to code is " 尾部带有空格,因此追加后能自然衔接:

Learning to code is awesome

第 3 步:整体校验最终代码。 合并起来即:

const someAdjective = "awesome";
let myStr = "Learning to code is ";
myStr += someAdjective;

自动测试是如何验证你的答案的

freeCodeCamp 的每一条挑战都在 # --hints-- 小节中声明了由代码生成的测试断言,本课的判定逻辑非常直白:

assert(typeof someAdjective !== 'undefined' && someAdjective.length > 2);

这一条断言做了两件事:

  • typeof someAdjective !== 'undefined':确认 someAdjective 已被定义(没有被删除或改名为其他标识符);
  • someAdjective.length > 2:确认其值至少包含 3 个字符(length 属性返回字符串的字符数,> 2 即长度 ≥ 3)。

第二条断言检查追加动作是否真的使用了 +=

assert(__helpers.removeJSComments(code).match(/myStr\s*\+=\s*someAdjective\s*/).length > 0);

它先把代码中的注释剥离(removeJSComments),再用正则 myStr\s*\+=\s*someAdjective\s* 在源码中查找:\s* 允许任意数量空白,\+= 匹配 += 本身,从而放行 myStr += someAdjective 这类写法的同时,也接受诸如 myStr+=someAdjective(无空格)的合法变体;只要匹配到一次即通过。若你只写了 myStr = myStr + someAdjective,正则无法命中,测试会失败——因为这道题明确要求训练的目标语法是 +=

官方参考实现与两种常见变体

# --solutions-- 小节给出的官方参考解:

const someAdjective = "neat";
let myStr = "Learning to code is ";
myStr += someAdjective;

someAdjective = "neat"(4 个字符)满足长度约束,myStr += someAdjective 命中第二条正则断言。等价的可通过写法还包括:

// 变体一:把 += 展开成显式的自我赋值(但不符合题目第二条正则断言要求)
let myStr = "Learning to code is ";
myStr = myStr + someAdjective;
// 变体二:不同的空格排布,正则 \s* 同样放行
myStr   +=   someAdjective;

其中变体一虽然语义正确,但无法通过第 2 条 hint 的语法检测,这体现了 freeCodeCamp 挑战「既要结果正确、也要按指定语法实现」的教学设计。

常见错误与避坑清单

结合文档语义与 JavaScript 语法规则,初学者在本课最容易踩的坑有三个:

  1. 忘记空格:初始字符串 "Learning to code is " 的结尾空格是句子的断点,一旦删除,追加后就会拼成 Learning to code isawesome。回顾 Concatenating Strings with Plus Operator 中的提示——拼接不会自动补空格,需要自己维护。
  2. += 用在 const 声明的变量上myStr 一旦声明为 constmyStr += ... 等价于对常量重新赋值,会抛出 TypeError: Assignment to constant variable。这正是题目刻意使用 let myStr 的原因。
  3. someAdjective 保持空字符串或删除定义:会导致第一条 length > 2 断言失败,或直接因 typeof 检查未定义而不通过。

另外可以补充一点通用认知:当 += 一侧是字符串、另一侧是数字时,数字会被强制转换为字符串后拼接(如 "count: " += 3 得到 "count: 3")。不过本课范围内两侧均为字符串,无需过度发散。

在仓库中溯源:一条挑战课文的完整结构与校验链

把视角从「做题」拉回「课程工程」:这篇 .md 并非普通文档,而是被 freeCodeCamp 的课程流水线解析的结构化挑战文件。其内部段落由 # --description--# --instructions--# --hints--# --seed--# --solutions-- 等标记分隔,分别承载题干讲解、任务说明、断言代码、初始化代码与参考答案。

这些字段都受到 curriculum/schema/challenge-schema.js 中 Joi 校验规则的约束。例如该文件要求:

  • challengeType0~33 之间的必填数字(对应 challenge-schema.jschallengeType: Joi.number().min(0).max(33).required());
  • dashedName 必须匹配 ^[a-z0-9-]+$ 的 slug 规范;
  • id 是必填的 24 位十六进制 ObjectId(本课的 56533eb9ac21ba0edf2244ed 即为一例)。

与此同时,challengeType: 1packages/shared/src/config/challenge-types.ts 中被定义为 js:它的视图类型被映射为 classic、提交类型被映射为 tests,也就是说学员在经典代码编辑器里作答并触发测试断言,正是由这套类型配置驱动的。整条 Basic JavaScript 学习路径的顺序、标题与标识符,则统一登记在 curriculum/structure/blocks/basic-javascript.jsonchallengeOrder 数组中,本课位列其中。

小结

「Appending Variables to Strings」是 freeCodeCamp Basic JavaScript 字符串主题链条上的收口一课:它把「+ 拼接」「+= 累积」「变量参与拼接」三个知识点组合成一个真实可运行的最小示例。掌握它之后,你已经拥有了字符串构建中最核心的两块语法拼图——++= 都能安全地把字符串字面量或变量组织成你想要的长文本。本课的全部内容均可在仓库目录 curriculum/challenges/english/blocks/basic-javascript/ 中继续探索,相邻题目可作为下一组练习。

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