讲解

学完语法,最后沉淀一批跨越具体知识点的工程习惯。这些约定来自社区长期踩坑的共识,本身没有强制性,但遵守它们的代码 bug 更少、协作更顺。第一部分是「默认安全」:默认 const,需要重新赋值才 let,永不 var;相等永远 === 和 !==;函数参数做边界校验,异常尽早抛出;不写隐式类型转换的「聪明代码」,显式调用 Number/String/Boolean。

第二部分是「结构清晰」:函数保持短小,一个函数只做一件事,超过一屏就该拆分;用提前返回代替深层嵌套,让主逻辑保持在最浅缩进;变量和函数名见名知意——布尔用 is/has/can 开头,函数用动词开头(fetchUser、formatPrice),常量全大写;纯函数优先(相同输入永远相同输出、无副作用),它们可预测、可测试;魔法数字提取成有名字的常量。

第三部分是「健壮与协作」:外部数据(接口返回、用户输入、localStorage)一律不可信,解析加 try/catch、使用前先校验;不静默吞错,catch 里至少记日志;代码格式化交给 Prettier、静态检查交给 ESLint,把风格争议交给工具;写注释解释「为什么」而不是复述「做什么」。这些习惯单条看收益有限,组合起来就是专业与业余的分水岭。

示例

// 反例 vs 正例:同一个函数两种写法

// 反例:嵌套深、魔法数字、隐式转换、无校验
function getPriceBad(user, item) {
  if (user) {
    if (item) {
      if (user.level == 2) {
        return item.price * 0.8;
      } else {
        return item.price;
      }
    }
  }
}

// 正例:提前返回、命名常量、显式校验、纯函数
const VIP_LEVEL = 2;
const VIP_DISCOUNT = 0.8;

function getPrice(user, item) {
  if (!user || !item) throw new TypeError('user 和 item 必填');
  if (typeof item.price !== 'number' || item.price < 0) {
    throw new RangeError('价格必须是非负数字');
  }
  const isVip = user.level >= VIP_LEVEL;
  return isVip ? item.price * VIP_DISCOUNT : item.price;
}

console.log(getPrice({ level: 3 }, { price: 100 }));
console.log(getPrice({ level: 1 }, { price: 100 }));

// 外部数据防御性处理
function parseConfig(raw) {
  try {
    const config = JSON.parse(raw);
    return {
      theme: config.theme === 'dark' ? 'dark' : 'light', // 白名单收敛
      fontSize: Number.isFinite(config.fontSize) ? config.fontSize : 14,
    };
  } catch {
    return { theme: 'light', fontSize: 14 }; // 兜底默认值
  }
}
console.log(parseConfig('{"theme":"dark","fontSize":18}'));
console.log(parseConfig('坏数据'));

// 纯函数:好测试、可预测
const addTag = (tags, tag) => (tags.includes(tag) ? tags : [...tags, tag]);
console.log(addTag(['js'], 'web'), addTag(['js'], 'js'));

常见坑

  • 过早抽象:三行重复代码就急着抽函数、上设计模式。规则是「第三次重复再抽象」,错误的抽象比重复更难维护。
  • 注释复述代码:i++ // i 加一 是噪音。注释写意图、写坑、写为什么不那样做。
  • 一行流炫技:把五步链式调用塞成一行的「聪明」代码,三个月后没人敢动。可读性优先于行数。
  • 依赖口头约定:风格靠人盯总会失守,Prettier/ESLint 进 CI 才能强制执行,把争论留给工具。

小结

默认 const 与 ===、小函数早返回、见名知意、纯函数优先、外部数据不可信、不吞错、风格交给工具。下一章看看 ES2022 之后标准又添了哪些好用的新特性。