Published on

Javascript / Typescript 命名规范和最佳实践

Authors

Programs are meant to be read by humans and only incidentally for computers to execute.

-- Donald Knuth

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

-- Matin Fowler

There are only two hard things in Computer Science: cache invalidation and naming things.

-- Phil Karlton

编写代码从来不是一件容易的事情。代码除了要实现指定的业务功能,还要方便Ta人理解和维护,这就有点像写技术文章,既要解决现实中的问题,又要方便读者理解。

个人认为 命名 是软件开发工程师首项基本功,不管是领域驱动开发(DDD)还是重构,你都会遇到 命名 ,希望本篇文章可以帮助到那些想要编写出易于维护的代码的开发人员。

1. 通用原则

1.1 符合英语语法

既然使用英语来命名,单词拼写正确和符合语法规则是最基本的。为了方便Ta人阅读和理解,你需要知道:

1.词性(包括名词/复数,动词/分词,形容词,介词,连词,量词)

2.基本句型

示例

// ❌ 不符合语法
function completedTranslate(chapterIds: string[]) {
  ...
}

// ✅ 符合语法:动宾结构 或 谓语+宾语结构
function completeTranslation() {
  ...
}

vscode 单词拼写检查插件推荐:https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker

1.2 表达保持一致

当存在多种可能的表达词语时,选择一种然后统一。

示例:

// ❌ 存在多种表达获取的英文单词
function getUsers() {}
function fetchBooks() {}
function retriveAuthors() {}

// ✅
function fetchUsers() {}
function fetchBooks() {}
function fetchAuthors() {}

1.3 精准的描述

避免使用 data,info, flag,process,handle,maintain,manage,modify等这些宽泛的单词,应该使用具体业务上下文名称。

示例:

// ❌ data 无法表明具体返回的数据内容
function fetchData() {}

// ✅
function fetchUsers() {}

1.4 不要使用技术术语命名

使用技术术语命名是一种基于实现细节的命名方式,而实现细节是容易变化的,所以应该使用业务语言来命名。

示例:

// ❌
const bookList = ['战争与和平', '巴黎圣母院', '童年'];
const bookSet = new Set(['战争与和平', '巴黎圣母院', '童年']);
const bookMap = new Map([['firstBook', '战争与和平'], ['secondBook', '巴黎圣母院'], , ['thirdBook', '童年']])

// ❎
const books = ['战争与和平', '巴黎圣母院', '童年'];

// ✅
const bookNames = ['战争与和平', '巴黎圣母院', '童年'];

1.5 描述意图,而非实现细节

命名要对实现的细节进行抽象,而不是对实现细节的陈述。

示例:

// ❌
function processChapter(chapterId: string) {
    const chapter = this.repository.findByChapterId(chapterId); 
    if (chapter == null) { 
      throw new Error("Unknown chapter [" + chapterId + "]"); 
    } 
    chapter.setTranslationState(TranslationState.TRANSLATING);
    this.repository.save(chapter);
}

// ❎
function changeChapterToTranslating(chapterId: string) {
  ...
}

// ✅
function startTranslation(chapterId: string) {
  ...
}

1.6 使用足够详尽的命名

在不看函数的文档的前提下,通过名称可以尽可能地理解其意图。

示例:

// ❌
function findBooks(author) {}

// ✅
function findBooksByAuthor(author) {}

1.7 避免缩写

不要用缩写和自己创造缩写,缩写非常影响可阅读性。

示例:

// ❌
const onItmClk = () => {}

// ✅
const onItemClick = () => {}

2. 最佳实践

2.1 常量

命名规范:使用全大写的字母和下划线(UPPER_SNAKE_CASE)来组合命名,下划线用以分割单词。

英文语法:名词或名词短语

示例

// ✅
const DAYS_UNTIL_TOMORROW = 1;

const PI = 3.14;

const MAX_COUNT = 100;

2.2 变量

普通变量

命名规范:小驼峰式

英文语法:名词或名词短语

布尔型变量

命名规范:小驼峰式

英文语法:形容词,动词的过去分词(-ed)和现在进行时(-ing),复合词,系表结构

示例1

const visible = true; // 形容词
const enabled = false; // 动词的过去分词
const loading = true; // 动词的现在进行时
const buttonDisabled = false; //复合词中形容词放在最后

示例2

前缀示例中文含义等同
shouldshouldUpdate是否应该更新
isisVisible, isHidden, isScrollable, isLoading是否可见,是否隐藏,是否可滚动,是否加载中visible, hidden, scrollable, loading
hashasEncryption是否有加密
areareEqual是否相等
cancanEdit是否能编辑editable
include
contain
needneedUpdate是否需要

数字型变量

命名规范:小驼峰式

英文语法:量词

示例

有意义的词语:width, length, count,size等,可以使用 numberOfXXX或者 xxxCount形式

// ❌ 名词的复数通常做数组列表
const rows = 100;

// ✅
const rowCount = 1000;
const pageSize = 200;
const numberOfErrors = 5;

数组类型变量

命名规范:小驼峰式

英文语法:名词复数或名词短语复数

示例

const fruits = ['banana', 'avocado', 'tomato'];

fruits.forEach((fruit, idx) => {});

字典(Map)类型变量

命名规范:小驼峰式

英文语法:名词复数或名词短语复数

示例

const usersByID = {
	id12345: {
    name: 'peter',
    id: 'id12345',
    age: '18'
  }
}

2.3 函数

函数通常都是执行一个动作,所以函数应该是动词开头(动宾结构),React函数组件是例外,需要用名词。

返回布尔值的函数

命名规范:小驼峰式

英文语法:系表结构,和布尔型变量类似

示例

//1.使用 is, are, has, can, need,include/contain 等 作为前缀

//2.is + 形容词

//3.has + 名词

//4.can + 动词

//5.need + 动词

//6.include / contain + 名词

// value string is ISBN ?
function isISBN(value: string) {
  ...
}

// compare date A and date B
function compareDate(dataA:Date, dateB:Date){
  ...
}

// element contains iframe ?
function containsIframe(element) {
  ...
}

返回其它值的函数

命名规范:小驼峰式

英文语法:动宾结构

示例

//1.使用 get, fetch, retrive 作为前缀
//2.+[ ? ] 需要返回的
//3.如果返回的是数组,记得复数
    
function getTemperature() { return temperature }

function getEggs() { return eggs }

无返回值得函数

命名规范:小驼峰式

英文语法:动词或动宾结构

示例

function setLanguageModal() {}

function launch(options) {}

A/HC/LC 通用模式

prefix? + action (A) + high context (HC) + low context? (LC)
示例前缀动作 (A)High context (HC)Low context (LC)
getUsergetUser
getUserMessagesgetUserMessages
handleClickOutsidehandleClickOutside
shouldDisplayMessageshouldDisplayMessage

2.4 复杂的函数

1.识别所有任务(单一职责,可测试)

2.分别为任务命名

3.创建子函数

4.总结出最终函数的名称

2.5 枚举

命名规范:大驼峰式,枚举值使用大驼峰 或 UPPER_SNAKE_CASE

英文语法:名词,形容词,名词短语

示例

enum UpperCamelCase { 
  CAPITALIZED_NAMES_WITH_UNDERSCORES = 0 
}

// 枚举值为名词
enum UserResponse {
  No,
  Yes
}

// 枚举值为形容词
enum Status { 
	Loading,
  Succeeded,
  Failed
}

2.6 类

大驼峰式:大驼峰式

英文语法:名词或名词短语

示例

class Point { }

类的对象

大驼峰式:大驼峰式

英文语法:名词或名词短语(口诀:美小圆旧黄,法国木书房。意思是定语顺序为:美丑-大小-形状-新旧-颜色-国家-材质-用途-主体。)

示例1

// ❌
const headerFancyVideo = new Video();
// ✅
const fancyHeaderVideo = new Video();

示例2

// 后置定语,放在后面
const usersWithPosts = [
  {
    id: 'userId',
    name: 'userName',
    posts: []
  }
]

类成员避免上下文冗余

class MenuItem {
	// ❌
  handleMenuItemClick = (event) => { ... }
  // ✅
  handleClick = (event) => { ... }
}

2.7 接口

大驼峰式:大驼峰式

英文语法:名词或名词短语,形容词

示例

interface Thenable { }

interface State { }

不使用 I 作为接口名的前缀

类和接口都是某种意义上的抽象和封装,继承时不需要关心它是一个接口还是一个类。如果用I前缀,当一个变量的类型更改了,比如由接口变成了类,那变量名称就必须同步更改。

// ❌
interface IState {
  name: string;
  age: number;
}

// ✅
interface State {
  name: string;
  age: number;
}

3. 业务名词表

命名中的业务名词,推荐使用DDD领域统一语言或者业务词汇表,这个名称表最好在项目的开始时就和业务,以及前后端一起确定所有业务对应的中英文对照。

4. 命名常用动词表

get 获取/ set 设置, add 增加/ remove 删除

create 创建/ destory 移除 start 启动/ stop 停止

open 打开/ close 关闭, read 读取/ write 写入

load 载入/ save 保存, create 创建/ destroy 销毁

begin 开始/ end 结束, backup 备份/ restore 恢复

import 导入/ export 导出, split 分割/ merge 合并

inject 注入/ extract 提取, attach 附着/ detach 脱离

bind 绑定/ separate 分离, view 查看/ browse 浏览

edit 编辑/ modify 修改, select 选取/ mark 标记

copy 复制/ paste 粘贴, undo 撤销/ redo 重做

insert 插入/ delete 移除, add 加入/ append 添加

clean 清理/ clear 清除, index 索引/ sort 排序

find 查找/ search 搜索, increase 增加/ decrease 减少

play 播放/ pause 暂停, launch 启动/ run 运行

compile 编译/ execute 执行, debug 调试/ trace 跟踪

observe 观察/ listen 监听, build 构建/ publish 发布

input 输入/ output 输出, encode 编码/ decode 解码

encrypt 加密/ decrypt 解密, compress 压缩/ decompress 解压缩

pack 打包/ unpack 解包, parse 解析/ emit 生成

connect 连接/ disconnect 断开, send 发送/ receive 接收

download 下载/ upload 上传, refresh 刷新/ synchronize 同步

update 更新/ revert 复原, lock 锁定/ unlock 解锁

check out 签出/ check in 签入, submit 提交/ commit 交付

push 推/ pull 拉, expand 展开/ collapse 折叠

begin 起始/ end 结束, start 开始/ finish 完成

enter 进入/ exit 退出, abort 放弃/ quit 离开

obsolete 废弃/ depreciate 废旧, collect 收集/ aggregate 聚集

reset 重置/

5. 命名翻译网站推荐:

https://unbug.github.io/codelf

https://fanyi.phpstudyhelper.com/