第 5 章:展示代码——程序员的必备技能
在技术写作中,代码展示是不可或缺的一部分。无论你是在编写技术文档、API 说明、教程还是个人笔记,都需要清晰、美观地展示代码片段。Markdown 为我们提供了两种主要的代码展示方式:行内代码和代码块。本章将详细介绍这些语法,帮助你成为代码展示的专家。
5.1 行内代码:用反引号包裹单个元素
行内代码用于在文本中嵌入简短的代码片段,如变量名、函数名、文件名或命令等。它使用单个反引号 ` 来包裹代码内容。
基本语法
在 JavaScript 中,可以使用 `console.log()` 函数来输出信息。
文件名通常是 `index.html` 或 `main.js`。
变量 `userName` 存储了用户的姓名。
渲染效果:
在 JavaScript 中,可以使用 console.log() 函数来输出信息。
文件名通常是 index.html 或 main.js。
变量 userName 存储了用户的姓名。
常见使用场景
1. 变量和函数名
函数 `calculateTotal()` 接收一个 `items` 数组作为参数,返回总价格。
渲染效果:
函数 calculateTotal() 接收一个 items 数组作为参数,返回总价格。
2. 文件路径和文件名
请将配置文件保存为 `config.json`,并放置在 `/src/assets/` 目录下。
渲染效果:
请将配置文件保存为 config.json,并放置在 /src/assets/ 目录下。
3. 命令行指令
使用 `npm install` 命令安装依赖包。
运行 `git status` 查看当前仓库状态。
渲染效果:
使用 npm install 命令安装依赖包。
运行 git status 查看当前仓库状态。
4. 键盘快捷键
按 `Ctrl+C` 复制选中的文本。
使用 `Cmd+Shift+P` 打开命令面板。
渲染效果:
按 Ctrl+C 复制选中的文本。
使用 Cmd+Shift+P 打开命令面板。
5. HTTP 状态码和错误代码
服务器返回了 `404` 错误,表示页面未找到。
成功的请求通常返回 `200` 状态码。
渲染效果:
服务器返回了 404 错误,表示页面未找到。
成功的请求通常返回 200 状态码。
转义反引号
如果你需要在行内代码中显示反引号本身,可以使用双反引号来包裹:
要创建行内代码,请使用 `` ` `` 符号包裹文本。
渲染效果:
要创建行内代码,请使用 ` 符号包裹文本。
最佳实践
1. 保持简洁
行内代码应该用于简短的代码片段,通常不超过一行:
# ✅ 好的用法
调用 `getUserInfo()` 函数获取用户信息。
# ❌ 不好的用法
调用 `function getUserInfo() { return fetch('/api/user').then(res => res.json()); }` 函数。
2. 明确语义
使用行内代码来明确标识技术术语:
# ✅ 清晰的技术术语
在 React 中,`useState` 是一个重要的 Hook。
# ❌ 普通文本
在 React 中,useState 是一个重要的 Hook。
3. 与标点符号的配合
# 正确的标点符号使用
请检查 `package.json` 文件中的依赖项。
函数 `getData()` 返回一个 Promise 对象。
5.2 围栏代码块:展示多行代码
当需要展示多行代码时,围栏代码块是最佳选择。它使用三个反引号 ``` 来创建代码块,可以保持代码的原始格式和缩进。
基本语法
```
function greetUser(name) {
console.log("Hello, " + name + "!");
return "Welcome to our website!";
}
greetUser("Alice");
```
渲染效果:
function greetUser(name) {
console.log("Hello, " + name + "!");
return "Welcome to our website!";
}
greetUser("Alice");
代码块的特点
1. 保持原始格式
代码块会保持你输入的所有空格、制表符和换行:
```
if (user.isLoggedIn) {
showDashboard();
} else {
redirectToLogin();
}
```
渲染效果:
if (user.isLoggedIn) {
showDashboard();
} else {
redirectToLogin();
}
2. 支持多种编程语言
```
<!-- HTML 示例 -->
<div class="container">
<h1>欢迎使用我们的应用</h1>
<p>这是一个示例页面。</p>
</div>
```
渲染效果:
<!-- HTML 示例 -->
<div class="container">
<h1>欢迎使用我们的应用</h1>
<p>这是一个示例页面。</p>
</div>
3. 展示配置文件
```
{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"react": "^18.0.0",
"axios": "^0.27.0"
}
}
```
渲染效果:
{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"react": "^18.0.0",
"axios": "^0.27.0"
}
}
使用场景
1. 函数和类定义
```
class UserManager {
constructor() {
this.users = [];
}
addUser(user) {
this.users.push(user);
console.log(`用户 ${user.name} 已添加`);
}
getUser(id) {
return this.users.find(user => user.id === id);
}
}
```
2. 命令行操作序列
```
# 克隆仓库
git clone https://github.com/username/project.git
# 进入项目目录
cd project
# 安装依赖
npm install
# 启动开发服务器
npm start
```
3. 配置文件示例
```
# .env 文件配置
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
API_KEY=your_api_key_here
PORT=3000
NODE_ENV=development
```
5.3 语法高亮:让代码更易读
通过在代码块的开始标记后指定编程语言,可以启用语法高亮,让代码更加美观和易读。
基本语法
```javascript
function calculateArea(radius) {
const pi = Math.PI;
return pi * radius * radius;
}
const area = calculateArea(5);
console.log(`圆的面积是: ${area}`);
```
渲染效果:
function calculateArea(radius) {
const pi = Math.PI;
return pi * radius * radius;
}
const area = calculateArea(5);
console.log(`圆的面积是: ${area}`);
常用语言标识符
1. 前端开发
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>我的网页</title>
</head>
<body>
<h1>欢迎访问</h1>
</body>
</html>
```
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>我的网页</title>
</head>
<body>
<h1>欢迎访问</h1>
</body>
</html>
```css
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
.button:hover {
background-color: #0056b3;
}
```
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
.button:hover {
background-color: #0056b3;
}
2. 后端开发
```python
def fibonacci(n):
"""计算斐波那契数列的第n项"""
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
# 计算前10项
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
```
def fibonacci(n):
"""计算斐波那契数列的第n项"""
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
# 计算前10项
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
```java
public class Calculator {
public static void main(String[] args) {
Calculator calc = new Calculator();
int result = calc.add(10, 20);
System.out.println("结果: " + result);
}
public int add(int a, int b) {
return a + b;
}
public int multiply(int a, int b) {
return a * b;
}
}
```
public class Calculator {
public static void main(String[] args) {
Calculator calc = new Calculator();
int result = calc.add(10, 20);
System.out.println("结果: " + result);
}
public int add(int a, int b) {
return a + b;
}
public int multiply(int a, int b) {
return a * b;
}
}
3. 数据格式
```json
{
"user": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"preferences": {
"theme": "dark",
"language": "zh-CN"
},
"roles": ["user", "editor"]
}
}
```
{
"user": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"preferences": {
"theme": "dark",
"language": "zh-CN"
},
"roles": ["user", "editor"]
}
}
```yaml
# Docker Compose 配置
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
```
# Docker Compose 配置
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
4. 命令行和脚本
```bash
#!/bin/bash
# 备份数据库脚本
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/backup"
DB_NAME="myapp"
echo "开始备份数据库: $DB_NAME"
pg_dump $DB_NAME > "$BACKUP_DIR/backup_$DATE.sql"
if [ $? -eq 0 ]; then
echo "备份成功: backup_$DATE.sql"
else
echo "备份失败"
exit 1
fi
```
#!/bin/bash
# 备份数据库脚本
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/backup"
DB_NAME="myapp"
echo "开始备份数据库: $DB_NAME"
pg_dump $DB_NAME > "$BACKUP_DIR/backup_$DATE.sql"
if [ $? -eq 0 ]; then
echo "备份成功: backup_$DATE.sql"
else
echo "备份失败"
exit 1
fi
常用语言标识符列表
| 语言/格式 | 标识符 | 示例用途 |
|---|---|---|
| JavaScript | javascript, js | 前端脚本、Node.js |
| Python | python, py | 后端开发、数据分析 |
| Java | java | 企业级应用开发 |
| C++ | cpp, c++ | 系统编程、游戏开发 |
| HTML | html | 网页结构 |
| CSS | css | 样式设计 |
| JSON | json | 数据交换格式 |
| XML | xml | 配置文件、数据格式 |
| YAML | yaml, yml | 配置文件 |
| SQL | sql | 数据库查询 |
| Bash | bash, shell | 命令行脚本 |
| PowerShell | powershell, ps1 | Windows 脚本 |
| Markdown | markdown, md | 文档编写 |
| Dockerfile | dockerfile | 容器配置 |
| TypeScript | typescript, ts | 类型安全的 JavaScript |
语法高亮的最佳实践
1. 选择正确的语言标识符
# ✅ 正确:使用具体的语言标识符
```javascript
const message = "Hello, World!";
```
# ❌ 错误:使用错误的标识符
```js-script
const message = "Hello, World!";
```
2. 保持一致性
在同一份文档中,对相同语言使用相同的标识符:
# ✅ 一致使用 javascript
```javascript
// 第一个示例
```
```javascript
// 第二个示例
```
# ❌ 混合使用不同标识符
```javascript
// 第一个示例
```
```js
// 第二个示例
```
3. 为纯文本选择合适的标识符
# 配置文件内容
```text
DATABASE_URL=postgresql://localhost:5432/mydb
API_KEY=your_key_here
```
# 命令行输出
```console
$ npm install
npm WARN deprecated package@1.0.0
+ package@2.0.0
added 1 package in 2.5s
```
5.4 高级技巧:转义和特殊情况
在代码块中显示三个反引号
当你需要在代码块中展示 Markdown 代码块语法本身时,可以使用四个反引号:
````markdown
```javascript
const greeting = "Hello, World!";
console.log(greeting);
```
````
渲染效果:
```javascript
const greeting = "Hello, World!";
console.log(greeting);
```
代码块中的特殊字符
代码块会按原样显示所有字符,包括 Markdown 语法字符:
```markdown
# 这是一个标题
**这是粗体文本**
*这是斜体文本*
[这是一个链接](https://example.com)
```
渲染效果:
# 这是一个标题
**这是粗体文本**
*这是斜体文本*
[这是一个链接](https://example.com)
行内代码中的反引号
如果行内代码包含反引号,使用双反引号包裹:
要在代码中使用模板字符串,请使用 `` `Hello, ${name}!` `` 语法。
渲染效果:
要在代码中使用模板字符串,请使用 `Hello, ${name}!` 语法。
代码块的缩进
除了围栏代码块,你也可以使用缩进(4个空格或1个制表符)来创建代码块:
这是普通段落。
function example() {
console.log("这是缩进代码块");
}
这又是普通段落。
渲染效果:
这是普通段落。
function example() {
console.log("这是缩进代码块");
}
这又是普通段落。
注意: 围栏代码块(```)比缩进代码块更灵活,支持语法高亮,因此更推荐使用。
5.5 综合练习:编写技术教程
现在让我们通过一个完整的技术教程来练习本章学到的所有代码展示技巧。
练习:JavaScript 异步编程入门
# JavaScript 异步编程入门教程
## 什么是异步编程?
异步编程是一种编程范式,允许程序在等待某些操作完成时继续执行其他任务。在 JavaScript 中,常见的异步操作包括网络请求、文件读取和定时器。
## 1. 回调函数 (Callback)
最传统的异步处理方式是使用回调函数:
```javascript
function fetchUserData(userId, callback) {
// 模拟网络请求
setTimeout(() => {
const userData = {
id: userId,
name: "张三",
email: "zhangsan@example.com"
};
callback(null, userData);
}, 1000);
}
// 使用回调函数
fetchUserData(123, (error, user) => {
if (error) {
console.error("获取用户数据失败:", error);
} else {
console.log("用户数据:", user);
}
});
```
### 回调地狱问题
当需要进行多个异步操作时,回调函数会导致代码嵌套过深:
```javascript
// 这就是著名的"回调地狱"
fetchUserData(123, (error, user) => {
if (!error) {
fetchUserPosts(user.id, (error, posts) => {
if (!error) {
fetchPostComments(posts[0].id, (error, comments) => {
if (!error) {
console.log("评论:", comments);
}
});
}
});
}
});
```
## 2. Promise
`Promise` 是 ES6 引入的异步解决方案,可以有效解决回调地狱问题:
```javascript
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const userData = {
id: userId,
name: "张三",
email: "zhangsan@example.com"
};
resolve(userData);
}, 1000);
});
}
// 使用 Promise
fetchUserData(123)
.then(user => {
console.log("用户数据:", user);
return fetchUserPosts(user.id);
})
.then(posts => {
console.log("用户文章:", posts);
return fetchPostComments(posts[0].id);
})
.then(comments => {
console.log("文章评论:", comments);
})
.catch(error => {
console.error("操作失败:", error);
});
```
## 3. Async/Await
`async/await` 是基于 Promise 的语法糖,让异步代码看起来像同步代码:
```javascript
async function getUserInfo(userId) {
try {
const user = await fetchUserData(userId);
console.log("用户数据:", user);
const posts = await fetchUserPosts(user.id);
console.log("用户文章:", posts);
const comments = await fetchPostComments(posts[0].id);
console.log("文章评论:", comments);
return { user, posts, comments };
} catch (error) {
console.error("获取用户信息失败:", error);
throw error;
}
}
// 调用异步函数
getUserInfo(123)
.then(result => {
console.log("完整信息:", result);
})
.catch(error => {
console.error("处理失败:", error);
});
```
## 实际应用示例
让我们看一个实际的网络请求示例:
```javascript
// 使用 fetch API 获取数据
async function getWeatherData(city) {
const API_KEY = 'your_api_key_here';
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return {
city: data.name,
temperature: Math.round(data.main.temp - 273.15), // 转换为摄氏度
description: data.weather[0].description,
humidity: data.main.humidity
};
} catch (error) {
console.error('获取天气数据失败:', error);
throw error;
}
}
// 使用示例
getWeatherData('北京')
.then(weather => {
console.log(`${weather.city}的天气:`);
console.log(`温度: ${weather.temperature}°C`);
console.log(`描述: ${weather.description}`);
console.log(`湿度: ${weather.humidity}%`);
})
.catch(error => {
console.log('无法获取天气信息');
});
```
## 最佳实践
1. **优先使用 `async/await`**:代码更清晰易读
2. **始终处理错误**:使用 `try/catch` 或 `.catch()`
3. **避免在循环中使用 `await`**:考虑使用 `Promise.all()`
```javascript
// ❌ 避免:串行执行
async function fetchAllUsers(userIds) {
const users = [];
for (const id of userIds) {
const user = await fetchUserData(id); // 串行执行,效率低
users.push(user);
}
return users;
}
// ✅ 推荐:并行执行
async function fetchAllUsers(userIds) {
const promises = userIds.map(id => fetchUserData(id));
return await Promise.all(promises); // 并行执行,效率高
}
```
## 总结
异步编程是现代 JavaScript 开发的核心技能。从回调函数到 Promise,再到 `async/await`,每种方式都有其适用场景。掌握这些技术将帮助你编写更高效、更易维护的代码。
### 关键要点
- 使用 `Promise` 避免回调地狱
- 使用 `async/await` 让异步代码更易读
- 始终处理错误情况
- 合理使用并行执行提高性能
练习要点分析
这个综合练习展示了本章所有代码展示技巧的实际应用:
-
行内代码的使用:
- 函数名:
fetchUserData()、Promise、async/await - 技术术语:
callback、resolve、reject - API 相关:
fetch、response.json()
- 函数名:
-
代码块的多样化展示:
- JavaScript 函数定义
- 异步操作示例
- 错误处理代码
- 实际应用场景
-
语法高亮的正确使用:
- 所有代码块都使用了
javascript标识符 - 保持了一致的代码风格
- 展示了完整的代码逻辑
- 所有代码块都使用了
-
最佳实践的体现:
- 代码注释清晰
- 示例由简到复杂
- 包含了正确和错误的对比
本章小结
在这一章中,我们全面学习了 Markdown 中代码展示的各种技巧:
主要内容回顾
-
行内代码:
- 基本语法:
`code` - 适用场景:变量名、函数名、文件名、命令等
- 转义技巧:使用双反引号
- 基本语法:
-
围栏代码块:
- 基本语法:
``` - 保持原始格式和缩进
- 支持多行代码展示
- 基本语法:
-
语法高亮:
- 指定编程语言:
```javascript - 常用语言标识符
- 提升代码可读性
- 指定编程语言:
-
高级技巧:
- 转义反引号
- 嵌套代码块展示
- 特殊字符处理
最佳实践总结
- 选择合适的展示方式:短代码用行内,长代码用代码块
- 使用正确的语言标识符:启用语法高亮
- 保持一致性:同一文档中使用统一的标识符
- 注重可读性:合理使用注释和空行
- 处理特殊情况:掌握转义和嵌套技巧
下一步学习
在下一章中,我们将学习 GitHub Flavored Markdown (GFM) 的扩展语法,包括删除线、表情符号、自动链接等功能,让你的文档更加生动有趣。
练习建议:尝试为你熟悉的编程语言或技术栈编写一份技术教程,使用本章学到的代码展示技巧来提升文档的专业性和可读性。