- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
本文基于 zh.javascript.info(现代 JavaScript 教程)代码质量章节中的实战练习展开。该练习给出了一段“风格很差但功能正确”的
pow幂函数代码,要求读者逐行找出风格问题并修复。读完本文,你将能系统地识别函数签名空格、花括号位置、运算符两侧空格、分号缺失、超长行、多变量声明等常见风格缺陷,并掌握一套可直接套用的修复方法;文中还会结合 代码风格主文 的规则体系与 ESLint 等自动检查工具,帮助你建立可落地的代码风格习惯。
练习背景:它在教程中的位置与考察目标
这段练习位于教程的 1-js/03-code-quality/02-coding-style 目录下,是“代码风格”一章的第一个任务,题目本身存放在 task.md,参考答案存放在 solution.md。
该章的核心主张非常明确:“我们的代码必须尽可能的清晰和易读”,良好的代码风格是一项“编程艺术”——以正确且易于他人阅读的方式完成复杂任务。练习的目的正是把这一抽象原则落到具体代码上:题目给出的代码在语法上完全合法、能正确计算x的n次幂,但充斥着大量风格缺陷。学习者需要像“审稿人”一样,逐行挑出问题并给出修复版本。
原始代码:一段“能跑但难看”的 pow 函数
练习给出的原始代码如下(这就是 task.md 中待修复的版本):
function pow(x,n) { let result=1; for(let i=0;i<n;i++) {result*=x;} return result; } let x=prompt("x?",''), n=prompt("n?",'') if (n<=0) { alert(`Power ${n} is not supported, please enter an integer number greater than zero`); } else { alert(pow(x,n)) }功能上它完成了三件事:定义pow(x, n)幂函数;通过两次prompt获取x与n;当n <= 0时提示不支持,否则弹出计算结果。但这段代码在可读性上有大量问题,接下来我们对照 solution.md 中逐条标注的注释,逐一剖析。
逐条剖析:代码中的每一处风格缺陷
下面是在原始代码上标注出的全部问题。为了方便对照,先看带注释的完整版本:
function pow(x,n) // <- 参数之间没有空格 { // <- 花括号独占了一行 let result=1; // <- = 号两边没有空格 for(let i=0;i<n;i++) {result*=x;} // <- 没有空格 // { ... } 里面的内容应该在新的一行上 return result; } let x=prompt("x?",''), n=prompt("n?",'') // <-- 从技术的角度来看是可以的, // 但是拆分成 2 行会更好,并且这里也缺了空格和分号 ; if (n<=0) // <- (n <= 0) 里面没有空格,并且应该在本行上面加一个空行 { // <- 花括号独占了一行 // 下面的一行代码太长了,可以将其拆分成 2 行以提高可读性 alert(`Power ${n} is not supported, please enter an integer number greater than zero`); } else // <- 可以像 "} else {" 这样写在一行上 { alert(pow(x,n)) // 缺失了空格和分号 ; }缺陷一:函数签名中参数之间没有空格
function pow(x,n)中x与n之间缺少空格。教程的 代码风格主文 将“空格”视为代码风格的基础语法要素,并提供了完整的风格备忘图(见下图),其中明确要求:函数名与左括号之间、括号与参数之间都要有空格,参数之间也要有空格。
修复方式:function pow(x, n)。
缺陷二:花括号独占一行
原始代码把左花括号{放在了单独一行:
function pow(x,n) {主文在“花括号”一节中明确指出:在大多数 JavaScript 项目中,花括号采用“Egyptian” 风格(即 K&R 风格)—— 左花括号与相应的关键词位于同一行末尾,而不是另起一行,且左括号前应有一个空格:
if (condition) { // do this // ...and that }因此{应紧跟函数签名:function pow(x, n) {。类似的错误在后面的if (n<=0)与else块中重复出现,属于同一类问题。
缺陷三:赋值运算符=两侧没有空格
let result=1;中=两侧没有空格。主文要求“运算符周围要有空格”,这是提高可读性的基础规则。修复为let result = 1;。
缺陷四:for 循环整体压缩在一行、缺少空格、代码块未换行
for(let i=0;i<n;i++) {result*=x;}同时违反了几条规则:
for关键字与左括号之间没有空格(主文要求for、if、while等关键词后留空格);- 循环头部
i=0、i<n、i++内部以及分号后缺少空格; - 循环体
{result*=x;}被压在同一行。主文明确指出:{ ... }里面的内容应该在新的一行上。
修复为:
for (let i = 0; i < n; i++) { result *= x; }缺陷五:用逗号在一行内声明多个变量
let x=prompt("x?",''), n=prompt("n?",'')在语法上完全合法(这也是原注释所说“从技术的角度来看是可以的”),但把两次prompt挤在同一行,既缺空格、又缺分号,可读性差。拆成两行、每行一个变量声明更清晰:
let x = prompt("x?", ""); let n = prompt("n?", "");缺陷六:if 条件内部没有空格,且上方缺少空行
if (n<=0)中n<=0内部没有空格(应为n <= 0)。同时,这段if之前的let声明与if之间没有空行。主文在“缩进”一节中专门讲了垂直方向上的缩进:用空行把代码拆分成逻辑块。即使是一个函数,也应分割为“变量初始化 → 主逻辑 → 返回值”等逻辑块;写代码时不应出现连续超过 9 行都没有被垂直分割的情况。
因此,let声明与if之间应插入一个空行。
缺陷七:单行过长
alert(Power ${n} is not supported, please enter an integer number greater than zero);这一行太长。主文在“行的长度”一节中指出:没有人喜欢读一长串代码,最好将代码分割一下。一行最大长度应由团队达成一致(通常是 80 或 120 个字符)。模板字符串(反引号`)天然支持跨行,因此可以把这条提示信息拆成两行:
alert(`Power ${n} is not supported, please enter an integer number greater than zero`);主文中还给出了if条件过长时的拆行示范——把多个条件纵向排列,每个条件一行:
if ( id === 123 && moonPhase === 'Waning Gibbous' && zodiacSign === 'Libra' ) { letTheSorceryBegin(); }缺陷八:else 单独占一行
else独占一行不如写成} else {。主文在花括号一节的示例(if (condition) { ... })以及风格备忘图中都体现了这一点:闭合花括号与else、下一个左花括号连写在一行上,整体结构更紧凑、块归属一目了然。
缺陷九:函数调用缺少空格与分号
alert(pow(x,n))存在两个问题:嵌套调用pow(x,n)内部没有空格(应为pow(x, n)),且语句末尾缺少分号。主文在“分号”一节中强调:每一个语句后面都应该有一个分号,即使它可以被跳过——因为在极少数情况下,JavaScript 的换行符不会被解释为分号,容易埋下隐患(详见 分号一节)。修复为:
alert( pow(x, n) );修复后的完整版本
综合以上所有修正,solution.md 给出的参考答案如下:
function pow(x, n) { let result = 1; for (let i = 0; i < n; i++) { result *= x; } return result; } let x = prompt("x?", ""); let n = prompt("n?", ""); if (n <= 0) { alert(`Power ${n} is not supported, please enter an integer number greater than zero`); } else { alert( pow(x, n) ); }对比前后两个版本可以看到:函数体内,变量初始化、循环逻辑、返回值之间用空行做了垂直分割;for循环体独占一行并缩进两个空格;if/else以} else {形式连接;所有运算符、逗号、括号前后都保留了规范的空格;每条语句都以分号结尾。功能完全不变,但可读性有了质的提升。这也是 代码风格主文 开头给出的规范示例风格(主文中n < 0版本的完整范本可参见该文“语法”一节)。
从“改对”到“写对”:支撑这些规则的原理
练习只要求修复一段代码,但真正重要的是理解每条规则背后的理由。结合 代码风格主文,可以把本练习涉及的规则归纳为几组:
花括号:选择哪种写法
主文对比了if的四种写法:
if (n < 0) {alert(...)}—— 初学者常把花括号与语句挤在一行,非常不好;if (n < 0)换行后再写alert(...)、不加花括号 —— 永远不要这样做,添加新行很容易出错;if (n < 0) alert(...)单行无花括号 —— 如果代码很短,可以接受;if (n < 0) { ... }——最好的方式。
本练习中的if (n<=0)恰好属于第 1 类的变形(花括号另起一行),应改为第 4 类写法。对于极短语句(如if (cond) return null),单行写法也是可接受的,但块结构通常更具可读性。
缩进:水平与垂直两个维度
- 水平缩进:通常为 2 或 4 个空格(或 Tab)。如今空格更普遍,因为空格可以比 Tab 做出更灵活的缩进配置(例如把函数参数与左括号对齐)。本练习统一采用 2 空格缩进。
- 垂直缩进:用空行把代码拆分成逻辑块。本练习在
result初始化、for循环、return之间,以及let声明与if之间插入空行,正是这一原则的体现。
嵌套层级:尽量浅
主文建议尽量避免过深嵌套,例如循环内不要层层加if,可以用continue提前跳出:
for (let i = 0; i < 10; i++) { if (!cond) continue; ... // <- 没有额外的嵌套 }if/else与return的组合也可以达到同样效果:把“特殊情况”在一开始就处理掉(例如n < 0时直接return),主代码流就不需要额外嵌套。本练习的pow函数虽然嵌套不深,但else分支的写法同样可以套用这一思路——条件不满足时立即结束,主体逻辑平铺展开。
函数位置:先调用、后定义
主文指出,如果代码中有“辅助函数”与调用它们的代码,组织方式有三种:函数在上、调用在下;调用在上、函数在下;混合式。大多数情况下“先写调用代码、再写函数”更好,因为阅读时我们首先想知道的是“它做了什么”。本练习中pow先定义后调用,属于第 1 种方式,在课堂练习中完全合理;但在真实项目中,把“做什么”的调用代码放在前面往往更利于他人快速理解程序主干。
把规则自动化:风格指南与检查器(Linters)
人工逐行审查难免遗漏,团队协作时更需要统一标准。主文介绍了两类工具化手段:
风格指南
风格指南是“如何编写代码”的通用规则集,涵盖用哪个引号、缩进几个空格、一行最大长度等细节。当团队所有成员遵循同一份指南时,无论代码由谁编写,风格都是统一的。业界已有多种成熟方案可供选择(如 Google、Airbnb、Idiomatic.JS、StandardJS 等),初学者可以从本文这类基础规则起步,再挑选自己偏好的指南。
ESLint 等自动检查器
检查器(Linters)可以自动检查代码风格并提出改进建议,而且顺带能发现变量或函数名拼写错误等真实 bug——因此即使不打算固守某种风格,也建议安装一个。主文提到 JSLint、JSHint、ESLint 等工具,并给出了 ESLint 的启用流程:
- 安装 Node.js;
- 使用
npm install -g eslint安装 ESLint; - 在项目根目录创建
.eslintrc配置文件; - 在编辑器中安装/启用 ESLint 插件。
主文给出的.eslintrc示例:
{ "extends": "eslint:recommended", "env": { "browser": true, "node": true, "es6": true }, "rules": { "no-console": 0, "indent": 2 } }其中"extends": "eslint:recommended"表示基于 ESLint 的推荐规则集进行设置,然后通过"rules"覆盖或追加自定义规则——例如示例中把缩进规则设定为 2 空格("indent": 2),与本练习采用的缩进风格完全一致。把本练习中发现的“缺陷类型”(空格缺失、分号缺失、花括号位置、行过长等)交给检查器自动把关,正是“从人工修复到机器预防”的最佳实践路径。
总结:一份可复用的代码风格自查清单
回到本练习,把 solution.md 揭示的九类问题整理成清单,即可作为日常自查的速查表:
- 参数与括号:函数名与
(之间、参数之间、嵌套调用参数之间都要有空格; - 花括号位置:左花括号与关键词同行(K&R 风格),
} else {连写在一行; - 运算符空格:
=、<=、*=等运算符两侧保留空格; - 控制结构:
for、if、while后留空格,循环体内容换行、缩进; - 变量声明:每行一个变量,使用
let x = ...;完整写法并加结尾分号; - 空行分割:不同逻辑块之间用空行做垂直分割;
- 行长度:超过团队约定(通常 80/120 字符)时拆分,模板字符串可跨行;
- 分号:每条语句末尾都写分号;
- 嵌套深度:用
continue、提前return减少嵌套层级。
主文在“总结”一节给出的判断标准值得反复体会:当我们思考如何写“更好”的代码时,应该问自己两个问题——“什么可以让代码可读性更高、更容易被理解?”以及“什么可以帮助我们避免错误?”本练习的每一处修复,最终都服务于这两个目标。
- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
相关推荐
修复 JavaScript 糟糕代码风格:以 pow 函数练习剖析编码规范(javascript.info 编码风格实战)
修复 JavaScript 糟糕代码风格:以 pow 函数练习剖析编码规范(javascript.info 编码风格实战) 整洁、易读的代码,与正确运行的代码同
文档/教程前端终极idiomatic.js代码审查宝典:快速识别和修复JavaScript代码风格问题
终极idiomatic.js代码审查宝典:快速识别和修复JavaScript代码风格问题 idiomatic.js是一个专注于编写一致、地道JavaScript
1BRC代码风格:统一代码风格与格式化规范
1BRC代码风格:统一代码风格与格式化规范 概述 在十亿行挑战(1BRC)这个高性能计算项目中,代码风格的一致性对于项目维护和性能优化至关重要。本文深入探讨1B
性能测试大数据
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考