-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
86e49b1
commit 32c924a
Showing
2 changed files
with
394 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
--- | ||
title: JavaScript 和 TypeScript 最佳实践 | ||
published_at: 2024-11-29T15:00:00.000Z | ||
snippet: 这篇文章作者详细介绍了不少 JS 和 TS 中的最佳实践, 非常实用。 | ||
--- | ||
|
||
## JavaScript 和 TypeScript 核心概念 | ||
|
||
### 4 个基础特性 | ||
|
||
1. **原始类型(Primitives)** | ||
|
||
- 原始类型包括 5 种传统类型:`null`、`undefined`、`boolean`、`number`、`string`,以及新增的两种类型:`symbol` 和 `bigint`。 | ||
- **重点**: | ||
- `symbol` 主要用于创建对象的唯一键,避免键值冲突。 | ||
- 类型强制(Coercion):当调用原始类型的函数时,JavaScript 会用其对象包装器(如 `Boolean`、`Number`)包装原始值,从而实现调用。 | ||
|
||
2. **函数(Functions)** | ||
|
||
- **创建方式**: | ||
- 函数声明:`function functionName() {}` | ||
- 箭头函数:`() => {}` | ||
- 对象字面量中的方法:`{ key: function() {} }` | ||
- 类方法:`class MyClass { myMethod() {} }` | ||
- **最佳实践**: | ||
- 在顶层使用函数声明以利用提升(Hoisting)。 | ||
- 在嵌套函数中使用箭头函数。 | ||
- 单参数箭头函数省略括号:`val => val * 2`。 | ||
|
||
3. **对象(Objects)** | ||
|
||
- **创建方式**: | ||
- 对象字面量:`{ key: value }` | ||
- 使用 `new` 调用构造函数:`new Date()` | ||
- 类实例化:`class MyClass {}`。 | ||
- **对象字面量**:更适合组织数据和代码,避免使用类的复杂性。 | ||
- **类**: | ||
- 通常避免用类来处理 IO 数据或作为项目结构的核心。 | ||
- 适合动态数据和需要封装逻辑的场景,例如数据结构(如 `Map`)。 | ||
- **建议**: | ||
- 对于 IO 数据,使用接口(`interface`)定义数据结构,使用对象字面量组织相关方法。 | ||
|
||
4. **类型(Types)** | ||
- **定义方式**: | ||
- 类型别名:`type MyType = ...` | ||
- 接口:`interface MyInterface { ... }` | ||
- **使用场景**: | ||
- 使用类型别名定义联合类型或简单结构。 | ||
- 使用接口定义复杂对象结构。 | ||
|
||
--- | ||
|
||
### 脚本(文件)类型 | ||
|
||
1. **声明型(Declaration)** | ||
|
||
- 导出单个声明,例如枚举或类型:`HttpStatusCodes.ts`。 | ||
|
||
2. **模块型(Modular)** | ||
|
||
- 导出包含相关函数或变量的对象字面量:`UserRepo.ts`。 | ||
|
||
3. **库存型(Inventory)** | ||
|
||
- 存储全局共享的小型声明:`types.ts`。 | ||
|
||
4. **线性型(Linear)** | ||
- 执行一系列命令的文件:`setup-db.ts`。 | ||
|
||
--- | ||
|
||
### 文件组织结构 | ||
|
||
- **推荐顺序**: | ||
|
||
1. 变量(只读或常量) | ||
2. 类型 | ||
3. 运行逻辑(可选,保持短小) | ||
4. 函数 | ||
5. 类(仅限小型类,大型类应独立文件) | ||
|
||
- **注意事项**: | ||
- `export default` 始终放在文件末尾。 | ||
- 在线性脚本中,代码可按任务分组,而非按类型组织。 | ||
|
||
--- | ||
|
||
### 何时使用类? | ||
|
||
- **适合场景**: | ||
|
||
- 动态数据需要与方法紧密耦合。 | ||
- 需要封装状态和逻辑,例如数据结构(如 `Map`)。 | ||
- 需要依赖注入,确保在多个地方使用同一实例。 | ||
|
||
- **避免场景**: | ||
- 处理 IO 数据:类实例化时方法不会传递,需额外构造或使用静态方法。 | ||
- 项目核心架构:使用函数式或过程式编程简化项目,不依赖类的状态管理。 | ||
|
||
--- | ||
|
||
### 示例代码 | ||
|
||
#### 函数声明 vs 箭头函数 | ||
|
||
```typescript | ||
function declaredFunction() { | ||
console.log("Function declaration"); | ||
} | ||
|
||
const arrowFunction = (val: number) => val * 2; | ||
``` | ||
|
||
#### 对象字面量与类 | ||
|
||
```typescript | ||
// 对象字面量 | ||
const user = { | ||
name: "John", | ||
sayHello() { | ||
console.log(`Hello, ${this.name}`); | ||
}, | ||
}; | ||
|
||
// 类 | ||
class User { | ||
constructor(public name: string) {} | ||
sayHello() { | ||
console.log(`Hello, ${this.name}`); | ||
} | ||
} | ||
``` | ||
|
||
#### 使用接口和模块化脚本管理数据 | ||
|
||
```typescript | ||
// User.ts | ||
export interface IUser { | ||
name: string; | ||
age: number; | ||
} | ||
|
||
const User = { | ||
isValid(user: IUser): boolean { | ||
return !!user.name && user.age > 0; | ||
}, | ||
}; | ||
|
||
export default User; | ||
``` | ||
|
||
--- | ||
|
||
### 总结 | ||
|
||
- **优先使用函数声明和对象字面量**,简化代码结构。 | ||
- **避免使用类组织项目或处理 IO 数据**,改用接口和模块化脚本。 | ||
- 遵循文件组织规则,确保代码可维护性和清晰性。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
--- | ||
title: JavaScript 和 TypeScript 最佳实践 | ||
published_at: 2024-12-02T15:00:00.000Z | ||
snippet: 这篇文章作者详细介绍了不少 JS 和 TS 中的最佳实践, 非常实用。 | ||
--- | ||
|
||
## 命名规则 | ||
|
||
### 文件/文件夹 | ||
|
||
1. **文件夹**: | ||
|
||
- 一般用小写加连字符,例如 `shared-utils/`。 | ||
- React 中包含组件的文件夹可用首字母大写,例如 `Home/` 包含 `Home.tsx` 和 `Home.test.tsx`。 | ||
|
||
2. **文件命名**: | ||
- **声明脚本**:文件名应与声明名称匹配,例如导出 `useSetState` 的文件应命名为 `useSetState.ts`。 | ||
- **模块脚本**:使用 PascalCase,例如 `UserRepo.ts`。 | ||
- **库存脚本**:使用小写加连字符,例如 `shared-types.ts`。 | ||
- **线性脚本**:使用小写加连字符,例如 `setup-db.ts`。 | ||
- **辅助测试文件夹**:以双下划线包裹,例如 `__test-helpers__/`。 | ||
|
||
--- | ||
|
||
### 变量命名 | ||
|
||
1. **全局静态变量**: | ||
|
||
- 用大写加下划线(`UPPER_SNAKE_CASE`),例如:`const SALT_ROUNDS = 12;`。 | ||
- 简单的数组或对象(没有嵌套)也用 `UPPER_SNAKE_CASE`。 | ||
|
||
2. **局部变量**: | ||
|
||
- 在函数内部声明的变量使用 `camelCase`。 | ||
- 布尔变量一般以 `is` 开头,例如:`session.isLoggedIn`。 | ||
|
||
3. **相关变量分组**: | ||
- 使用单个声明块定义相关变量,提高代码可读性和性能,但不要过度使用。 | ||
```typescript | ||
const FOO_BAR = "abc", | ||
MAX_COUNT = 10; | ||
``` | ||
|
||
--- | ||
|
||
### 函数命名 | ||
|
||
1. **格式**: | ||
|
||
- 一般使用 `camelCase`。 | ||
- JSX 组件使用 `PascalCase`。 | ||
- 函数名应反映动作,使用动词格式,例如 `fetchName()`。 | ||
- 简单的常量返回函数可省略动词: | ||
|
||
```typescript | ||
const Errors = { | ||
SomeError: "Error message", | ||
EmailNotFound(email: string) { | ||
return `User with email "${email}" not found.`; | ||
}, | ||
} as const; | ||
``` | ||
|
||
2. **特殊规则**: | ||
- 辅助函数(仅限文件内部使用)用下划线开头,例如:`function _helperFn() {}`。 | ||
- IO 数据返回用 `fetch`,非 IO 数据返回用 `get`,例如: | ||
- `user.getFullName()` | ||
- `UserRepo.fetchUser()`。 | ||
|
||
--- | ||
|
||
### 对象命名 | ||
|
||
1. **不可变对象**: | ||
|
||
- 全局静态对象使用 `UPPER_SNAKE_CASE`。 | ||
- 模块或声明脚本导出的对象使用 `PascalCase`,并用 `as const` 标记为不可变。 | ||
|
||
2. **动态对象**: | ||
- 在函数内部的对象用 `camelCase`。 | ||
- 运行时返回的动态对象也用 `camelCase`。 | ||
|
||
--- | ||
|
||
### 类和枚举 | ||
|
||
1. **类**: | ||
|
||
- 类名用 PascalCase。 | ||
- 类的静态只读变量用 PascalCase,例如 `Dog.Species`。 | ||
- 实例变量和方法用 `camelCase`。 | ||
|
||
2. **枚举**: | ||
- 枚举名和键均用 PascalCase,例如: | ||
```typescript | ||
enum NodeEnvs { | ||
Dev = "development", | ||
Prod = "production", | ||
} | ||
``` | ||
|
||
--- | ||
|
||
### 类型和接口 | ||
|
||
1. **类型别名**: | ||
|
||
- 类型名以 `T` 开头,例如:`type TMouseEvent = React.MouseEvent<HtmlButtonElement>;`。 | ||
|
||
2. **接口**: | ||
- 接口名以 `I` 开头,例如:`interface IUser { name: string; email: string; }`。 | ||
|
||
--- | ||
|
||
### 注释规则 | ||
|
||
1. **函数注释**: | ||
|
||
- 使用 `/** Comment */` 格式,放在函数声明上方,首字母大写并以句号结束。 | ||
|
||
```typescript | ||
/** | ||
* Add two numbers. | ||
*/ | ||
function add(a: number, b: number): number { | ||
return a + b; | ||
} | ||
``` | ||
|
||
2. **代码块注释**: | ||
|
||
- 在函数内部用 `//` 注释,注释首字母大写并以句号结束。 | ||
|
||
3. **分隔代码块**: | ||
|
||
- 用 `// **** Section Name **** //` 分隔文件的主要部分(变量、类型、函数等)。 | ||
|
||
4. **复杂逻辑注释**: | ||
- 对复杂逻辑分块注释,用 `/** */` 分隔大的功能。 | ||
|
||
--- | ||
|
||
### 导入规则 | ||
|
||
1. **组织导入**: | ||
|
||
- 库在顶部,自己代码在下方。 | ||
- 相同目录的导入放在最底部。 | ||
- 超过字符限制的导入单独换行。 | ||
|
||
2. **示例**: | ||
|
||
```typescript | ||
import express from "express"; | ||
import { UserRepo } from "@src/repos/UserRepo"; | ||
import helpers from "./helpers"; | ||
``` | ||
|
||
--- | ||
|
||
### 示例脚本 | ||
|
||
1. **模块脚本**: | ||
|
||
```typescript | ||
// MailUtil.ts | ||
const SUPPORT_EMAIL = "[email protected]"; | ||
/** | ||
* Send an email. | ||
*/ | ||
function sendEmail(to: string, subject: string, body: string) { | ||
console.log(`Sending email to ${to}`); | ||
} | ||
export default { | ||
sendEmail, | ||
} as const; | ||
``` | ||
|
||
2. **声明脚本**: | ||
|
||
```typescript | ||
// EnvVars.ts | ||
export default { | ||
PORT: process.env.PORT, | ||
DB_HOST: process.env.DB_HOST, | ||
} as const; | ||
``` | ||
|
||
3. **线性脚本**: | ||
|
||
```typescript | ||
// server.ts | ||
import express from "express"; | ||
const app = express(); | ||
app.use(middleware); | ||
export default app; | ||
``` | ||
|
||
--- | ||
|
||
### 其他代码风格 | ||
|
||
1. **布尔表达式**: | ||
|
||
- 用括号提升可读性: | ||
```typescript | ||
if ((isFoo && isBar) || isBaz) { | ||
console.log("Condition met."); | ||
} | ||
``` | ||
|
||
2. **可选链**: | ||
|
||
- 使用 `?.` 替代 `foo && foo.bar`。 | ||
- 使用 `??` 替代 `(str || '')`。 | ||
|
||
3. **长条件语句**: | ||
|
||
- 每行一个逻辑条件,嵌套逻辑缩进。 | ||
```typescript | ||
if (user?.isActive && (role !== "ADMIN" || permissions?.length > 0)) { | ||
// Do something | ||
} | ||
``` | ||
|
||
4. **对象参数格式**: | ||
- 对象字面量的花括号放在函数参数同一行: | ||
```typescript | ||
doSomething("arg1", { key: "value" }, "arg2"); | ||
``` |