JavaScript 作为前端开发从业人员必须掌握的 3 大基础知识中最重要的一环, 也是平是接触时间最长, 写得最多的. 在开发过程中必然会遇到命名的问题, 你会词穷, 纠结, 惆怅吗? 本文的出现相信能够解决大部分烦恼, 让你轻松写出符合规范, 易读, 简短的代码.
本文将通过大量的实例来试图自圆其说, 形成一套系统化, 实用的变量命名理化体系. 通过按 JavaScript 的数据类型分类着手, 细到一个函数的参数命名, 并提供众多可选方案, 并尽量给出其适用范围和利弊.
需要注意的是由于个人写作水平, 和知识有限, 很多方面叙述上有些生硬, 在分类上也没有什么特别的依据, 文章也没有人审稿, 所以有什么纰漏还请留言告知. 由于写作仓促, 内容可能不全, 后续会随着工作和学习的深入而不断地调整和更新.
布尔值 (Boolean) 命名
Boolean 值是两种逻辑状态的变量, 它包含两个值: 真和假. 在 JavaScript 中对应 true 和 false, 在实践中通常使用数字 1 表示真值, 0 来表示假值.
虽然 Boolean 的状态只有两种但是在命名时可以进一步分类, 这里给出几种场景:
场景一: 表示可见性, 进行中的状态
解释: 可见性在通常指页面中的元素, 组件是否显示(或者组件挂载到 DOM 上, 但并不可见). 进行中主要是说明某种状态是处于持续进行中.
推荐命名方式为 is + 动词(现在进行时)/ 形容词, 同时这种方式也可以直接不写 is, 但是为了更好的作区分, 建议还是加上.
- {
- isShow: '是否显示',
- isVisible: '是否可见',
- isLoading: '是否处于加载中',
- isConnecting: '是否处于连接中',
- isValidating: '正在验证中',
- isRunning: '正在运行中',
- isListening: '正在监听中'
- }
注意: 在 Java 中使用这种方式是有一定副作用的, 为什么请移步: 为什么阿里巴巴禁止开发人员使用 "isSuccess" 作为变量名? https://zhuanlan.zhihu.com/p/54458588
场景二: 属性状态类
解释: 通常用来描述实体 (例如: html 标签, 组件, 对象) 的功能属性, 而且定法比较固定.
- {
- disabled: '是否禁用',
- editable: '是否可编辑',
- clearable: '是否可清除',
- readonly: '只读',
- expandable: '是否可展开',
- checked: '是否选中',
- enumberable: '是否可枚举',
- iterable: '是否可迭代',
- clickable: '是否可点击',
- draggable: '是否可拖拽'
- }
场景三: 配置类, 选项类
解释: 主要是指组件功能的开启与关闭, 功能属性的配置.
这是一种比较常见的情景, 目前命名方式也有很多种, 但是归纳起来也不多. 推荐使用 withXx 来表示组件在基本功能形态外的其它功能, 比如组件的基础功能到高级功能的开启; 使用 enableXx 来表示组件某些功能的开启; 使用 allowXx 来表示功能属性的配置; 使用 noXx 用于建议功能使用者这个不建议开启.
- {
- withTab: '是否带选项卡',
- withoutTab: '不带选项卡',
- enableFilter: '开启过滤',
- allownCustomScale: '允许自定义缩放',
- shouldClear: '是否清除',
- canSelectItem: '是否能选中元素',
- noColon: '不显示 label 后面的冒号',
- checkJs: '检查 Js',
- emitBOM: 'Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files.'
- }
注意: 如果嫌分类太多, 可以只使用其中一种方式, 比如在 Typescript 中使用了 allownXx 和 noXx.
除了上面这些带有特定的前置介词, 动词方式外还有一些在语义上带有疑问性质的组合通常也是作为 Boolean 命名的一种参考.
- {
- virtualScroll: '是否启用虚拟滚动模式',
- unlinkPanels: '在范围选择器里取消两个日期面板之间的联动',
- validateEvent: '输入时是否触发表单的校验'
- }
函数命名
函数在不同的上下文中的叫法也不一样, 在对象中称为方法, 在类中有构造函数, 在异步处理时有回调函数, 还有立即执行函数, 箭头函数, 柯里函数等.
函数命名的方式常常是和业务逻辑耦合在一起的, 但是在命名规则上也有一些常见的模式可以遵循.
场景一: 事件处理
事件处理函数是前端平时用到最多的, 包括浏览器原生事件, 异步事件和组件自定义事件. 在写法上最常见的两种命名分别为 onXx,onXxClick 和 handleXx,handleXxChange.
这里如何在二者之间选择, 可以从二方面来归类. 一是, 原生事件采用 onXx, 而自定义事件使用 handleXx. 二是, 事件主动监听采用 onXx, 被动处理使用 handleXx.
从实践及三大主流框架的文档关于事件部分的内容来看, 推荐使用 handleXx 这种方式, 而在表单提交的时候通常采用 onSubmit 函数.
其实, 在实际项目中很少严格这样来命名事件处理函数, 因为这种方式有一定的局限性, 比如点击按钮打开一个对话框, 使用 handleOpenDlg 和 onOpenDlg 都没有直接写 openDlg 方便, 如果页面有多个不同功能的对话框采用这种方式会显得变量名过长, 而 handle 和 on 就显得没有必要了, 比如 hanldeOpenCommentDlg 就没有 openCommentDlg 直白.
下面列出了一些约定成俗的适用例子:
- {
- onSubmit: '提交表单',
- handleSizeChange: '处理分页页数改变',
- handlePageChange: '处理分页每页大小改变',
- onKeydown: '按下键'
- }
场景二: 异步处理
这里主要是指在写数据层服务, 状态管理中的 Action 命名, 以及 Ajax 回调的命名规则.
- {
- getUsers: '获取用户列表',
- fetchToken: '取得 Token',
- deleteUser: '删除用户',
- removeTag: '移除标签',
- updateUsrInfo: '更新用户信息',
- addUsr: '添加用户',
- createAccount: '创建账户'
- }
- {
- toTplDetail: '跳转到模板详情页面',
- navigateToHome: '导航到首页',
- jumpHome: '跳转首页',
- goHome: '跳转首页',
- redirectToLogin: '重定向到登录页',
- switchTab: '切换 Tab 选项卡',
- backHome: '回到主页'
- }
- {
- formatTimeFilter: '在 AngularJs 和 vue 中, 通常用于过滤器命名',
- storeCtrl: '用于 AngularJs 定义控制器方法',
- formatPipe: '用于 Angular 中, 标识管道方法',
- $emit: 'Vue 中的实例方法',
- $$formatters: 'AngularJs 中的内置方法',
- beforeCreate: 'Vue 的生命周期命名',
- componentWillMount: 'React 生命周期命名',
- componentDidMount: 'React 生命周期命名',
- afterContentInit: 'Anuglar 生命周期命名',
- afterViewChecked: 'Angula 生命周期命名',
- httpProvider: 'AngularJs 服务',
- userFactory: '工厂函数',
- useCallback: 'React 钩子函数'
- }
- {
- getItemById: '根据 ID 获取数据元素',
- getItemsBySelected: '根据传入的已选列表 ID 来获取列表全部数据',
- queryUserByUid: '根据 UID 查询用户'
- }
- {
- formatDate: '格式化日期',
- convertCurrency: '转换货币单位',
- inverseList: '反转数据列表',
- toggleAllSelected: '切换所有已选择数据状态',
- parseXml: '解析 XML 数据',
- flatSelect: '展开选择数据',
- sortByDesc: '按降序排序'
- }
- {
- users: '用户列表',
- userList: '用户列表',
- tabOptions: '选项卡选项',
- stateMaps: '状态映射表',
- selectedNodes: '选中的节点',
- btnGroup: '按钮组',
- userEntities: '用户实体'
- }
- // 最常见组合
- {
- title: '标题',
- value: 'ID 值'
- }
- // 组合二
- {
- label: '标签名',
- value: 'ID 值'
- }
- // 组合三
- {
- name: '元素名',
- id: 'ID 值'
- }
- // 组合四
- {
- field: '字段',
- value: '标识',
- index: '索引'
- }
- {
- activeTab: '当前选中选项卡',
- currentPage: '当前页',
- selectedData: '当前选项中数据',
- }
- {
- swapData: '临时交换数据',
- tempData: '临时数据',
- dataSnapshot: '数据快照'
- }
- // for 循环
- for (let i = 0; i <10; i++) {
- for (let j = 0; j < 10; j++) {
- for (let k = 0; k < 10; k++) {
- // do something
- }
- }
- }
- for (let i = 0, lens = this.options.length; i < lens; i++) {
- // do something
- }
- // forEach
- users.forEach((item, index) => {
- // do something
- })
- menus.forEach((menu, index) => {
- if (menu.children) {
- menu.children.forEach((subMenu, subIndex) => {
- if (subMenu.children) {
- subMenu.children.forEach((grandMenu, grandIndex) => {
- // 一个不常用的示例
- })
- }
- })
- }
- })
- {
- oldVal: '旧值',
- newVal: '新值'
- }
- // 组合一
- {
- from: '从...',
- to: '到...'
- }
- // 组合二
- {
- prev: '上一个...',
- next: '下一个...',
- cur: '当前'
- }
- // 组合三
- {
- source: '源',
- target: '目标'
- }
- // 组合四
- {
- start: '开始',
- end: '结束'
- }
- demoPromise.then(res => {
- // do something
- })
- // 传入单个字符
- function upper(ch) {
- }
- // 数量重复
- function repeat(str, n)
- // 正则
- 'abab'.replace(reg, 'bb')
- {
- load: '已完成加载',
- unload: '资源正在被卸载',
- beforeunload: '资源即将被卸载',
- error: '失败时',
- abort: '中止时',
- focus: '元素获得焦点',
- blur: '元素失去焦点',
- cut: '已经剪贴选中的文本内容并且复制到了剪贴板',
- copy: '已经把选中的文本内容复制到了剪贴板',
- paste: '从剪贴板复制的文本内容被粘贴',
- resize: '元素重置大小',
- scroll: '滚动事件',
- reset: '重置',
- submit: '表单提交',
- online: '在线',
- offline: '离线',
- open: '打开',
- close: '关闭',
- connect: '连接',
- start: '开始',
- end: '结束',
- print: '打印',
- afterprint: '打印机关闭时触发',
- click: '点击',
- dblclick: '双击',
- change: '变动',
- select: '文本被选中被选中',
- keydown/keypress/keyup: '按键事件',
- mousemove/mousedown/mouseup/mouseleave/mouseout: '鼠标事件',
- touch: '轻按',
- contextmenu: '右键点击 (右键菜单显示前)',
- wheel: '滚轮向任意方向滚动',
- pointer: '指针事件',
- drag/dragstart/dragend/dragenter/dragover/dragleave: '拖放事件',
- drop: '元素在有效释放目标区上释放',
- play: '播放',
- pause: '暂停',
- suspend: '挂起',
- complete: '完成',
- seek: '搜索',
- install: '安装',
- progress: '进行',
- broadcast: '广播',
- input: '输入',
- message: '消息',
- valid: '有效',
- zoom: '放大',
- rotate: '旋转',
- scale: '缩放',
- upgrade: '更新',
- ready: '准备好',
- active: '激活'
- }
- {
- assignedEvent: '分配事件',
- closedEvent: '关闭事件',
- labeledEvent: '标签事件',
- lockedEvent: '锁事件',
- deployedEvent: '部署事件'
- }
- {
- selectAll: '选择所有',
- cellClick: '当某个单元格被点击时会触发该事件',
- sortChange: '当表格的排序条件发生变化的时候会触发该事件'
- }
- // Redux 的 actionType
- LOAD_SUCCESS
- LOAD_FAIL
- TOGGLE_SHOW_HISTORY
- ON_PLAY
- ON_LOAD_START
- FETCH_SONGS_REQUEST
- RECEIVE_PRODUCTS
- // ngrx
- const SET_CURRENT_USER = '[User] Set current';
- const ADD_THREAD = '[Thread] Add';
- const UPDATE_TRIP_SUCCESS = 'Update [Trip] Success';
- // 日期, 时间
- // --------------------------------------------------------
- sentAt: '发送时间'
- addAt: '添加时间'
- updateAt: '更新时间'
- startDate: '开始日期'
- endDate: '结束日期'
- startTime: '开时时间'
- endTime: '结束时间'
- GitHub GraphQL API V4 https://developer.github.com/v4/
- Facebook GraphQL API Reference
- VS Code API
- tsconfig JSON http://json.schemastore.org/tsconfig
- Typescript Compiler Options
- Airbnb JavaScript Style Guides https://github.com/airbnb/javascript
- style-guides JavaScript
来源: https://segmentfault.com/a/1190000020039039