避免意外的值促成了意外的结果

在下面的代码中,我们的目的是判断草稿中的邀请人和当前邀请人是否为同一个人,但这里存在潜在的问题,如果draftInviterUserId和inviterUserId的值并非是我们期望的值,而是undefined、null或空字符串,那这个条件也会成立,但结果将会带来bug。

bad

const isSameInviter = draftInviterUserId === inviterUserId;

bood

const isValidValue = (value) => {
  // 这里我们没有使用!!value,而是使用冗余的方案,是为了避免在语法上会被转换为假值,但在业务上是合法的值,比如0
  return id !== undefined && id !== null && id !== ''
}

const isSameInviter = () => {
  if (!isValidValue(draftInviterUserId) || !isValidValue(invterUserId)) {
    return false
  }

  return draftInviterUserId === inviterUserId
}

从上面来看,一个简单的相等比较,其中就存在2个容易被忽略陷阱。

避免重复判断

bad

if (currentTheme?.id && currentTheme?.id === 'xxx') {
 // do something
}

good

if (currentTheme?.id && currentTheme.id === 'xxx') {
 // do something
}

currentTheme.id在前面已经使用?.进行了判断,后面没必要再次判断一遍

tip:
使用?.操作符的目的是为了安全地访问currentTheme可能为null或undefined的情况
因为当currentTheme为null或undefined,直接访问currentTheme.id会抛出错误,使用?.操作符,表达式会返回undefined而不是抛出错误

变量声明位置

bad

const query = {
  ...
}

if (type === '1') {
    api.getListData(query)
} else {
    api.getData()
}

good

if (type === '1') {
    const query = {
      ...
    }
    api.getListData(query)
} else {
    api.getData()
}
  1. 变量作用域最小化原则:query 只在 if 分支中使用,不需要在 else 分支中使用,因此应该将其定义在实际需要的作用域内。
  2. 代码可读性:将相关的代码放在一起,使逻辑更清晰和内聚。
  3. 避免不必要的内存占用:当走 else 分支时,不需要创建 query 对象。

对象常量

bad

/**
 * 主题类型枚举
 * @readonly
 * @enum {number}
 * @property {number} LANDMARK - 地标类型
 * @property {number} VILLAGE - 村庄类型
 * @property {number} MIXED - 地标和专题的混合类型
 */
export const THEME_TYPES = {
  LANDMARK: 0,
  VILLAGE: 1,
  MIXED: 2,
};

good

/**
 * 主题类型枚举
 * @readonly
 * @enum {number}
 * @property {number} LANDMARK - 地标类型
 * @property {number} VILLAGE - 村庄类型
 * @property {number} MIXED - 地标和专题的混合类型
 */
export const THEME_TYPES = Object.freeze({
  LANDMARK: 0,
  VILLAGE: 1,
  MIXED: 2,
});

即使是const声明对象也会能够被意外赋值,使用Object.freeze就可以避免


热饭班长
3.7k 声望434 粉丝

先去做,做出一坨狗屎,再改进。