# js开发

## 规则（Rules）

# JS编码规范

## 适用对象和范围

本规范适用于所有使用原生JavaScript编写前端功能代码的场景，包括DOM操作、事件处理、数据请求和API联调。

---

## 1. 变量声明规范

**规则**：必须使用 `const`（优先）或 `let` 声明变量，禁止使用 `var`。

- ✅ 正确：`const API_URL = '/api/users';` / `let currentPage = 1;`
- ❌ 错误：`var API_URL = '/api/users';`

**违反后果**：`var` 存在函数级作用域提升问题，可能导致变量污染和难以排查的bug。

---

## 2. 命名规范

**规则**：必须按照以下命名法命名标识符。

| 标识符类型 | 命名法 | 示例 |
|-----------|--------|------|
| 常量 | UPPER_SNAKE_CASE | `const API_BASE_URL = '/api/v1';` |
| 变量/函数参数 | camelCase | `let userName = '张三';` |
| 函数 | camelCase（动词开头） | `function loadUserList() {}` |
| 类/构造函数 | PascalCase | `class UserService {}` |
| DOM引用变量 | camelCase + `$`前缀 | `const $submitBtn = ...;` |

- ✅ 正确：`const MAX_COUNT = 100;` / `let userEmail = '';` / `function fetchData() {}`
- ❌ 错误：`const max_count = 100;` / `let user_email = '';` / `function Fetch_Data() {}`

**违反后果**：命名不一致导致代码可读性差，其他开发者难以理解和维护。

---

## 3. 缩进规范

**规则**：统一使用 **2个空格** 缩进，禁止使用Tab。

- ✅ 正确：
```javascript
function loadData() {
  const url = '/api/data';
  fetch(url)
    .then(res => res.json())
    .then(data => {
      console.log(data);
    });
}
```

- ❌ 错误：
```javascript
function loadData() {
    const url = '/api/data';
    fetch(url)
        .then(res => res.json())
        .then(data => {
            console.log(data);
        });
}
```

**违反后果**：缩进不一致导致代码结构混乱，增加代码审查难度。

---

## 4. 语句分隔符规范

**规则**：每条语句末尾必须加分号 `;`。

- ✅ 正确：`const name = '张三';` / `loadData();`
- ❌ 错误：`const name = '张三'` / `loadData()`

**违反后果**：JavaScript的自动分号插入（ASI）机制在某些情况下会错误推断分号位置，导致运行时错误。

---

## 5. 引号规范

**规则**：字符串统一使用单引号 `'`，模板字符串使用反引号 `` ` ``。

- ✅ 正确：`const name = '张三';` / `` const msg = `你好，${name}`; ``
- ❌ 错误：`const name = "张三";`

**违反后果**：引号使用不一致影响代码风格统一性，增加合并冲突概率。

---

## 6. 注释规范

**规则**：函数和模块必须使用JSDoc格式注释。

```javascript
/**
 * 加载用户列表
 * @param {number} page - 页码，从1开始
 * @param {number} [size=20] - 每页条数
 * @returns {Promise<Array>} 用户列表数据
 */
async function loadUserList(page, size = 20) {
  // ...
}
```

- ✅ 正确：函数有JSDoc注释，包含 `@param` 和 `@returns`
- ❌ 错误：函数无注释，或只写 `// 加载用户列表`

**违反后果**：缺少JSDoc注释导致IDE无法提供类型提示，降低开发效率。

---

## 7. 事件绑定规范

**规则**：必须使用 `addEventListener` 绑定事件，禁止使用 `onclick`/`onchange` 等HTML属性绑定。

- ✅ 正确：`$submitBtn.addEventListener('click', handleSubmit);`
- ❌ 错误：`<button onclick="handleSubmit()">提交</button>`

**违反后果**：HTML属性绑定混合了结构和行为，不利于维护，且只能绑定一个事件处理函数。

---

## 8. DOM操作规范

**规则**：优先使用 `querySelector`/`querySelectorAll`，避免使用 `getElementById` 等旧API。

- ✅ 正确：`document.querySelector('#user-table')`
- ❌ 错误：`document.getElementById('user-table')`

**违反后果**：旧API选择能力有限（只能按ID/Class/TagName选择），无法使用CSS选择器的灵活性。

---

## 9. 数据请求规范

**规则**：使用 `fetch` API进行数据请求，必须包含错误处理（`.catch()` 或 `try/catch`）。

- ✅ 正确：
```javascript
async function fetchData() {
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('请求失败:', error);
    throw error;
  }
}
```

- ❌ 错误：
```javascript
function fetchData() {
  return fetch(url).then(res => res.json());
}
```

**违反后果**：缺少错误处理导致网络异常时程序静默失败，用户无法获知错误信息。

---

## 10. 调试规范

**规则**：禁止在最终代码中保留 `console.log` 调试语句，错误日志应使用 `console.error`。

- ✅ 正确：`console.error('请求失败:', error);`
- ❌ 错误：`console.log('请求结果:', data);`

**违反后果**：生产环境中的 `console.log` 会暴露内部数据，影响性能，且显得代码不专业。

---

## 11. 安全规范

**规则**：禁止使用 `eval()` 或 `new Function()` 执行动态代码。

- ❌ 错误：`eval('alert("hello")');` / `new Function('return ' + userInput)();`

**违反后果**：`eval()` 会执行任意JavaScript代码，存在严重的安全风险（XSS攻击）。

---

## 12. 代码分离规范

**规则**：数据定义（data.js）和功能实现（index.js）必须分离到独立文件。

- ✅ 正确：`data.js` 存放常量和工具函数，`index.js` 存放功能逻辑
- ❌ 错误：所有代码写在一个文件中

**违反后果**：代码耦合度高，难以维护和测试。

## 方法（Methods）

# JS编码方法

## 前置条件

- [ ] 已明确要编写JS功能代码的模块名称和功能描述
- [ ] 已了解API接口地址和参数（如有）
- [ ] 已确认HTML中DOM元素的选择器（ID、class等）
- [ ] 已知道数据模型定义

## 流程概览

理解需求 → 设计数据结构(data.js) → 编写功能代码(index.js) → 验证功能完整性

## 详细步骤

### 步骤1：理解需求
分析需求文档，提取以下信息：
- 功能模块名称（用作模块名）
- 功能描述和交互逻辑
- API接口地址和参数（如有）
- 数据结构定义

## 技巧（Tips）

# JS编码技巧

## 1. 合理使用模板字符串

**适用场景**：需要拼接字符串和变量时。

**具体做法**：使用反引号模板字符串替代 `+` 拼接。

**对比说明**：

| 维度 | 传统拼接 | 模板字符串 |
|------|---------|-----------|
| 可读性 | 多变量时难以阅读 | 清晰直观 |
| 多行支持 | 需加 `\n` 和 `+` | 天然支持多行 |
| 表达式 | 需先计算再拼接 | 可直接嵌入 `${表达式}` |

**示例**：
```javascript
// ❌ 不推荐
const html = '<div class="card">' +
  '<h3>' + user.name + '</h3>' +
  '<p>' + user.email + '</p>' +
  '</div>';

// ✅ 推荐
const html = `
  <div class="card">
    <h3>${user.name}</h3>
    <p>${user.email}</p>
  </div>
`;
```

**注意事项**：模板字符串中的 `${}` 内可以放任意JavaScript表达式，包括三元运算符和函数调用。

---

## 2. 使用事件委托处理动态元素

**适用场景**：列表中的按钮点击、表格行操作等需要为动态生成的元素绑定事件的场景。

**具体做法**：在父元素上绑定事件，通过 `event.target.closest()` 判断具体触发元素。

**对比说明**：

| 维度 | 直接绑定 | 事件委托 |
|------|---------|---------|
| 动态元素 | 新增元素需重新绑定 | 自动生效 |
| 性能 | N个元素绑N个监听器 | 只需1个监听器 |
| 内存 | 多元素时占用大 | 节省内存 |

**示例**：
```javascript
// ❌ 不推荐：逐个绑定
document.querySelectorAll('.btn-delete').forEach(btn => {
  btn.addEventListener('click', handleDelete);
});

// ✅ 推荐：事件委托
$table.addEventListener('click', (event) => {
  const btn = event.target.closest('.btn-delete');
  if (!btn) return;
  handleDelete(parseInt(btn.dataset.id, 10));
});
```

**注意事项**：`closest()` 方法会向上查找匹配的祖先元素，包括自身。如果点击的是按钮内部的图标或文字，也能正确找到按钮。

---

## 3. 使用 DocumentFragment 批量渲染

**适用场景**：需要向DOM中插入大量（超过10个）元素时。

**具体做法**：创建 `DocumentFragment`，在内存中构建DOM树，最后一次性追加到真实DOM。

**对比说明**：

| 维度 | 直接 innerHTML | DocumentFragment |
|------|---------------|-----------------|
| 性能 | 每次操作触发重排 | 只触发一次重排 |
| 事件 | 需重新绑定 | 事件委托不受影响 |
| 安全性 | 可能被XSS攻击 | 安全 |

**示例**：
```javascript
// ✅ 推荐：批量渲染
function renderUsers(users) {
  const fragment = document.createDocumentFragment();
  users.forEach(user => {
    const tr = document.createElement('tr');
    tr.innerHTML = `<td>${user.name}</td><td>${user.email}</td>`;
    fragment.appendChild(tr);
  });
  $table.innerHTML = '';
  $table.appendChild(fragment);
}
```

**注意事项**：`DocumentFragment` 在内存中操作，不会引起回流（reflow），适合大量数据渲染。

---

## 4. async/await 优于 .then().catch()

**适用场景**：处理异步操作，特别是多个异步操作有依赖关系时。

**具体做法**：使用 `async/await` + `try/catch` 替代链式 `.then().catch()`。

**对比说明**：

| 维度 | .then().catch() | async/await |
|------|----------------|-------------|
| 可读性 | 嵌套时难以跟踪 | 像同步代码一样直观 |
| 错误处理 | 需在每个链上catch | 统一try/catch |
| 调试 | 断点难以定位 | 可以逐行调试 |

**示例**：
```javascript
// ❌ 不推荐：回调地狱
function loadData() {
  fetch(url)
    .then(res => res.json())
    .then(data => {
      return fetch(data.nextUrl);
    })
    .then(res => res.json())
    .then(data => render(data))
    .catch(err => console.error(err));
}

// ✅ 推荐：async/await
async function loadData() {
  try {
    const res1 = await fetch(url);
    const data1 = await res1.json();
    const res2 = await fetch(data1.nextUrl);
    const data2 = await res2.json();
    render(data2);
  } catch (error) {
    console.error('加载数据失败:', error);
  }
}
```

**注意事项**：`await` 只能在 `async` 函数中使用。如果需要在顶层使用，可以用 IIFE（立即执行函数表达式）包裹。

---

## 5. 常见问题速查

| 问题 | 原因 | 解决方案 |
|------|------|---------|
| `this` 指向错误 | 回调函数中丢失上下文 | 使用箭头函数或 `.bind(this)` |
| 异步数据未加载完成就渲染 | 未等待Promise完成 | 使用 `await` 等待数据返回后再渲染 |
| 事件重复绑定 | 多次调用初始化函数 | 在绑定前先 `removeEventListener` |
| 内存泄漏 | 事件绑定后未解绑 | 在组件销毁时调用 `removeEventListener` |
| 表单提交页面刷新 | 未阻止默认行为 | 在事件回调中调用 `event.preventDefault()` |
