第三章:Console 面板精通:console.log 的进阶用法

说实话,很多人用 console.log 就只会扔一个变量进去。

我见过不少同事,调试时满屏都是 undefined 和 [object Object]。嗯,这其实挺浪费 Console 面板的潜力的。今天我就带你看看,console.log 到底能玩出什么花来。

3.1 占位符:让输出更清晰

console.log 支持类似 C 语言的 printf 风格占位符。我个人习惯用这个来格式化输出,比拼接字符串清爽多了。

const user = { name: '张三', age: 28 };
console.log('用户信息:%s,年龄:%d', user.name, user.age);
// 输出:用户信息:张三,年龄:28

// 更实用的场景:调试对象
const data = { id: 1, title: '调试技巧' };
console.log('数据对象:%o', data);  // %o 会展开对象
小技巧:%o 和 %O 的区别你知道吗?%o 输出 DOM 元素时显示为 HTML 结构,%O 则显示为对象属性。调试 DOM 节点时特别好用。

我在项目中遇到过一个问题:后端返回的嵌套对象,用 console.log 直接打印根本看不清层级。后来用 %o 配合 JSON.stringify,一眼就找到了数据缺失的字段。

3.2 分组:让日志不再杂乱

当你的日志输出量很大时,分组功能简直是救星。

console.group('用户登录流程');
console.log('开始验证用户名');
console.log('验证密码');
console.group('权限检查');
console.log('检查角色');
console.log('检查资源权限');
console.groupEnd();
console.log('登录完成');
console.groupEnd();

你想想看,如果不用分组,这些日志会混在一起。一旦流程复杂,你根本分不清哪条日志属于哪个阶段。

注意:group 默认是展开状态。如果你希望默认折叠,用 console.groupCollapsed()。我经常用它来隐藏那些「我知道没问题但还是要打印」的日志。

3.3 表格:数组和对象的可视化

console.table 是我最常用的调试工具之一。为什么?因为人类天生对表格敏感。

const users = [
  { name: '李四', age: 25, role: 'admin' },
  { name: '王五', age: 30, role: 'user' },
  { name: '赵六', age: 22, role: 'editor' }
];

console.table(users);

这段代码会在 Console 面板里生成一个漂亮的表格。你可以点击列头排序,还能直接复制数据。我曾经用它来对比两个 API 返回的数据差异,比肉眼一行行看快多了。

还有个隐藏用法:你可以指定只显示某些列。

console.table(users, ['name', 'role']);  // 只显示 name 和 role 两列

3.4 计时:性能分析的入门工具

想知道某段代码跑了多久?别用 Date.now() 手动减了,console.time 和 console.timeEnd 就是干这个的。

console.time('数据加载');
// 模拟异步请求
setTimeout(() => {
  console.timeEnd('数据加载');  // 输出:数据加载: 1000.123ms
}, 1000);
核心要点:time 和 timeEnd 的标签必须一致。我见过有人复制粘贴时忘了改标签,结果计时永远对不上。

更进阶的用法:console.timeLog 可以在计时过程中输出中间结果。

console.time('循环处理');
for (let i = 0; i < 1000000; i++) {
  if (i === 500000) {
    console.timeLog('循环处理', '已处理一半');
  }
}
console.timeEnd('循环处理');

嗯,这个在优化长列表渲染时特别有用。你可以精确知道哪个阶段最耗时。

console.warn、console.error、console.assert 的使用场景

这三个方法,说白了就是给日志打标签。但很多人用错了地方。

3.5 console.warn:黄色警告,别忽视

console.warn 输出黄色背景的警告信息。它不会中断代码执行,但会在 Console 面板里显示一个警告图标。

function parseConfig(config) {
  if (!config.version) {
    console.warn('配置缺少 version 字段,将使用默认版本');
    config.version = '1.0.0';
  }
  // 继续处理...
}

我建议在以下场景使用 warn:

  • API 返回了非关键性错误,但需要提醒开发者
  • 某个功能即将废弃,提示迁移
  • 用户输入了不推荐的值,但程序还能继续运行
个人习惯:我会在 warn 里加上「[Deprecated]」或「[Fallback]」前缀,方便后期 grep 搜索。

3.6 console.error:红色警报,必须处理

console.error 输出红色背景的错误信息。它同样不会中断代码,但会附带堆栈信息。

try {
  const data = JSON.parse(response);
} catch (e) {
  console.error('JSON 解析失败,原始数据:', response, '错误:', e);
  // 这里可以继续执行降级逻辑
}

我曾经犯过一个错误:在 catch 里只用了 console.log。结果线上出了问题,日志里全是普通信息,根本分不清哪些是真正的错误。后来我强制团队规定:所有 catch 块必须用 console.error。

避坑指南:console.error 不等于 throw。它只是打印错误,不会终止程序。如果你需要中断执行,还是要用 throw new Error()。

3.7 console.assert:条件断言的利器

console.assert 接受一个条件和一个消息。条件为 false 时,输出错误信息。

function calculateDiscount(price, rate) {
  console.assert(price > 0, '价格必须大于0,当前值:', price);
  console.assert(rate >= 0 && rate <= 1, '折扣率必须在0-1之间');
  return price * rate;
}

你想想看,这比写 if 判断然后 console.error 简洁多了。一行代码搞定断言和日志。

但要注意:console.assert 不会抛出异常。它只是打印错误。所以它适合用在「非致命但需要关注」的校验场景。

我记得有一次调试一个复杂的表单验证逻辑,用了十几个 console.assert 来校验每个字段的中间状态。配合分组功能,一眼就看出是哪个校验条件没通过。

3.8 综合实战:一个完整的调试示例

最后,我给你看一个我在项目中实际用过的调试代码片段。

function fetchUserData(userId) {
  console.assert(userId > 0, '无效的用户ID');
  
  console.time('获取用户数据');
  console.groupCollapsed('用户数据请求');
  
  console.log('请求参数:%o', { userId });
  
  return fetch(`/api/user/${userId}`)
    .then(res => {
      if (!res.ok) {
        console.warn('请求状态异常:', res.status);
      }
      return res.json();
    })
    .then(data => {
      console.table([data], ['id', 'name', 'email']);
      console.timeEnd('获取用户数据');
      console.groupEnd();
      return data;
    })
    .catch(err => {
      console.error('获取用户数据失败:', err);
      console.groupEnd();
    });
}

这段代码里,我用了 assert 做前置校验,time/timeEnd 做性能监控,group 做日志分组,table 做数据展示,warn 和 error 做分级提示。一个函数就把 Console 面板的潜力发挥到了极致。

嗯,下次调试的时候,试试这些方法。你会发现 Console 面板远比你想象的强大。