程序员命名备忘单

139 阅读5分钟

说明:本文由 ChatGPT 翻译自 Naming cheatsheet,博主仅校对。

起名并非易事,本文试图让它变得更容易一些。

虽然这些建议适用于任何编程语言,但我将使用 JavaScript 来实践它们。

使用英文

使用英语来命名变量和函数。

/* Bad */
const primerNombre = 'Gustavo'
const amigos = ['Kate', 'John']

/* Good */
const firstName = 'Gustavo'
const friends = ['Kate', 'John']

不管你喜不喜欢,英语都是编程中的主导语言:所有编程语言的语法,以及无数的文档和教材都是用英语编写的。用英语编码可以大大提高代码的连贯性。

命名约定

选择 一个 命名约定并遵循它。它可以是小驼峰式 camelCase、大驼峰式 PascalCase、蛇形 snake_case 或其他任何风格,只要保持一致即可。许多编程语言都有它们自己的命名约定传统;请查看你所用语言的文档或研究一些受欢迎的 Github 存储库!

/* Bad */
const page_count = 5
const shouldUpdate = true

/* Good */
const pageCount = 5
const shouldUpdate = true

/* Good as well */
const page_count = 5
const should_update = true

S-I-D 原则

一个名字必须具备这样的特点:短小直观描述性

  • 短小。名字不应该太长,这样记忆和打字都会变得很困难;
  • 直观。名字必须读起来自然,与口语尽可能接近;
  • 描述性。名字必须以最有效的方式反映它所做/拥有的。
/* Bad */
const a = 5 // "a" could mean anything
const isPaginatable = a > 10 // "Paginatable" sounds extremely unnatural
const shouldPaginatize = a > 10 // Made up verbs are so much fun!

/* Good */
const postCount = 5
const hasPagination = postCount > 10
const shouldPaginate = postCount > 10 // alternatively

避免使用缩写

要使用缩写。缩写对代码的可读性毫无贡献。找到一个简短、描述性的名称可能很难,但缩写并不是这样做的借口。

/* Bad */
const onItmClk = () => {}

/* Good */
const onItemClick = () => {}

避免上下文重复

如果一个名称已经包含在定义它的上下文中了,就不应该再重复这个上下文。在不影响可读性的前提下,应该从名称中删除有关上下文的定义。

class MenuItem {
  /* Method name duplicates the context (which is "MenuItem") */
  handleMenuItemClick = (event) => { ... }

  /* Reads nicely as `MenuItem.handleClick()` */
  handleClick = (event) => { ... }
}

反映预期结果

名称应该反映预期的结果。

/* Bad */
const isEnabled = itemCount > 3
return <Button disabled={!isEnabled} />

/* Good */
const isDisabled = itemCount <= 3
return <Button disabled={isDisabled} />

命名函数

A/HC/LC 模式

命名函数时,有一个有用的模式:

prefix? + action (A) + high context (HC) + low context? (LC)

请查看下表,了解如何应用此模式。

名称前缀动作 (A)High context (HC)Low context (LC)
getUsergetUser
getUserMessagesgetUserMessages
handleClickOutsidehandleClickOutside
shouldDisplayMessageshouldDisplayMessage

注意: HC 和 LC 的顺序影响变量的含义。例如,shouldUpdateComponent 表示 即将更新一个组件,而shouldComponentUpdate 则表示 组件 将自行更新,你只是控制 何时 更新。换句话说,HC 彰显了变量的含义。

动作

函数名称中的动词部分,是描述函数 做什么 的最重要的部分。

get

立即访问数据(即内部数据的快捷获取器)。

function getFruitCount() {
  return this.fruits.length
}

在执行异步操作时,也可以使用 get

async function getUser(id) {
  const user = await fetch(`/api/user/${id}`)
  return user
}

set

以声明的方式将变量从值 A 设置为值 B

let fruits = 0

function setFruits(nextFruits) {
  fruits = nextFruits
}

setFruits(5)
console.log(fruits) // 5

reset

将变量设置回其初始值或初始状态。

const initialFruits = 5
let fruits = initialFruits
setFruits(10)
console.log(fruits) // 10

function resetFruits() {
  fruits = initialFruits
}

resetFruits()
console.log(fruits) // 5

remove

从某处移除某物。

例如,在搜索页面上有一组可供选择的过滤器,从集合中移除其中一个过滤器应该是 removeFilter,而 deleteFilter(这也是在英语中自然表达的方式):

function removeFilter(filterName, filters) {
  return filters.filter((name) => name !== filterName)
}

const selectedFilters = ['price', 'availability', 'size']
removeFilter('price', selectedFilters)

delete

从存在的某一范围中彻底消除某物。

想象你是一名编辑,有一篇臭名昭著的帖子需要清除。一旦你点击了一个闪亮的“删除帖子”按钮,CMS 将执行 deletePost 操作,而 removePost

function deletePost(id) {
  return database.find({ id }).delete()
}

remove 还是 delete

removedelete 之间的差异不那么明显时,建议看看它们的相反动作 - addcreateaddcreate 之间的关键区别在于 add 需要一个目的地,而 create 不需要目的地。你将一个条目添加到 某处,但你不会“将其 创建到某处”。这样一来,只需将 removeadd 配对,将 deletecreate 配对即可。

这里 有详细说明。

compose

从现有数据中创建新数据。主要适用于字符串、对象或函数。

function composePageUrl(pageName, pageId) {
  return pageName.toLowerCase() + '-' + pageId
}

handle

处理一个动作。通常在命名回调方法时使用。

function handleLinkClick() {
  console.log('Clicked a link!')
}

link.addEventListener('click', handleLinkClick)

Context

Context 指的是函数操作对象的领域。

函数通常是在 某些东西 上进行操作的。重要的是说明函数的可操作领域,或者至少表明预期的数据类型是什么。

/* A pure function operating with primitives */
function filter(list, predicate) {
  return list.filter(predicate)
}

/* Function operating exactly on posts */
function getRecentPosts(posts) {
  return filter(posts, (post) => post.date === Date.now())
}

一些特定于语言的假设可能允许省略 Context。例如,在 JavaScript 中,filter 通常作用于数组上。显式添加 context 的 filterArray 显得有点画蛇添足。

前缀

前缀增强了变量的含义。它很少用于函数名称。

is

描述当前 context 的特征或状态(数据类型通常为 boolean)。

const color = 'blue'
const isBlue = color === 'blue' // characteristic
const isPresent = true // state

if (isBlue && isPresent) {
  console.log('Blue is present!')
}

has

描述当前 context 是否具有特定的值或状态(数据类型通常为 boolean)。

/* Bad */
const isProductsExist = productsCount > 0
const areProductsPresent = productsCount > 0

/* Good */
const hasProducts = productsCount > 0

should

映射为一条伴随某个特定动作并带有肯定意向的条件语句(通常为 boolean)。

function shouldUpdateUrl(url, expectedUrl) {
  return url !== expectedUrl
}

min/max

表示最小或最大值。用于描述边界或限制。

/**
 * Renders a random amount of posts within
 * the given min/max boundaries.
 */
function renderPosts(posts, minPosts, maxPosts) {
  return posts.slice(0, randomBetween(minPosts, maxPosts))
}

prev/next

指示在当前 context 下变量的先前或下一个状态。用于描述状态转换。

async function getPosts() {
  const prevPosts = this.state.posts

  const latestPosts = await fetch('...')
  const nextPosts = concat(prevPosts, latestPosts)

  this.setState({ posts: nextPosts })
}

单复数

与前缀类似,变量名可以根据它们包含的值是单个值还是多个值而变为单数或复数。

/* Bad */
const friends = 'Bob'
const friend = ['Bob', 'Tony', 'Tanya']

/* Good */
const friend = 'Bob'
const friends = ['Bob', 'Tony', 'Tanya']