[译] 你不知道的 console 命令

相比使用 console.log 去输出值,咱们有更多的方式去调试 JavaScript。你觉得我要聊调试器么?不不不你想错了。

告诉写 JavaScript 的人应该使用浏览器的调试器去调试代码,这看来很不错,而且确定有其适用的时间和场合。可是大多数时候你仅仅只想查看一段特定的代码是否执行或者一个变量的值是什么,而不是迷失在 RxJS 代码库或者一个 Promise 库的深处。前端

然而,尽管 console.log 有其适用的场合,大多数人仍然没有意识到 console 自己除了基础 log 还有许多选择。合理使用这些方法能让调试更简单、更快速,而且更加直观。android

console.log()

不少人不知道经典的 console.log 其实有着丰富的函数特性。尽管大多数人只使用 console.log(object) 这种语法,但你仍然能写 console.log(object, otherObject, string) 而且它会将全部东西都整齐的打印出来。有时候确实很方便。ios

不止那些,这儿还有另外一种格式:console.log(msg, values)。这个执行方式和 C 或者 PHP 的 sprintf 很类似。git

console.log('I like %s but I do not like %s.', 'Skittles', 'pus');
复制代码

会准确的输出你所预期的东西。github

> I like Skittles but I do not like pus.
复制代码

通常的占位符有 %o(这是字符 o,不是 0)表示一个对象,%s 表示一个字符串,以及 %d 表明一个小数或者整数。后端

你可能并不认为另外一个有趣是 %c。实际上它是做为 CSS 值的占位符。数组

console.log('I am a %cbutton', 'color: white; background-color: orange; padding: 2px 5px; border-radius: 2px');
复制代码

后面的值能够一直添加,在这里没有「结束标签」确实有点怪异。可是你能够像这样将它们隔开。浏览器

这并不优美,也不是特别的有用。固然这也不是真实的按钮。bash

真的颇有用吗?不太认同。ide

console.dir()

一般来看,console.dir() 功能和 log() 很是类似,尽管看起来有略微不一样。

下拉小箭头展现的对象信息和 console.log 的视图里同样。可是在你观察元素节点的时候,二者结果会很是有趣而且大相径庭。

let element = document.getElementById('2x-container');
复制代码

这是 log 输入 element 的输出:

我打开了一些元素节点。清晰的展现了 DOM 节点,尽收眼底,并且咱们还能够跳转到子DOM节点。可是 console.dir(element) 给咱们一个意外不一样的输出。

这是一种更对象化的方式去观察元素节点。也许在某些像监测元素节点的时候,这样的结果才是你所想要的。

console.warn()

多是 log() 最直接明显的替换,你能够用相同的方式使用 console.warn()。惟一的区别在于输出是一抹黄色。确切的说,输出是一个 warn 级别而不是一个 info 级别的信息,所以浏览器的处理稍稍有些不一样。在一堆杂乱的输出中高亮你的输出是颇有效果的。

不过,这还有一个更大的优势。由于输出是一个 warn 级别而不是一个 info 级别,你能够将全部的 console.log 过滤掉只留下 console.warn。这有时在那些不停输出一堆无用和无心义的东西到浏览器的随意的应用程序中是很是有用。屏蔽干扰能更容易的看到你本身的输出。

console.table()

使人惊讶的是这个并无广为人知,可是 console.table() 方法更偏向于一种方式展现列表形式的数据,这比只扔下原始的对象数组要更加整洁。

举一个例子,下面是数据的列表。

const transactions = [{
  id: "7cb1-e041b126-f3b8",
  seller: "WAL0412",
  buyer: "WAL3023",
  price: 203450,
  time: 1539688433
},
{
  id: "1d4c-31f8f14b-1571",
  seller: "WAL0452",
  buyer: "WAL3023",
  price: 348299,
  time: 1539688433
},
{
  id: "b12c-b3adf58f-809f",
  seller: "WAL0012",
  buyer: "WAL2025",
  price: 59240,
  time: 1539688433
}];
复制代码

若是使用 console.log 去列出以上信息,咱们能获得一些中看不中用的输出:

▶ (3) [{…}, {…}, {…}]
复制代码

这小箭头容许你点击并会展开这个数组,但这并非咱们想要的「一目了然」。

console.table(data) 的输出则对咱们更为有帮助。

第二个可选参数是你想要显示列表的某列。默认是整个列表,可是咱们也能这样作。

> console.table(data, ["id", "price"]);
复制代码

咱们获得这样的输出,仅仅只展现 id 和 price。在有着大量不相关信息的庞杂对象中很是有用。index 列是自动生成的而且据我所知是不会消失。

值得一提的是在最右一列头部的右上角有个箭头能够颠倒次序。点击了它,会排序整个列。很是方便的找出一列的最大或者最小值,或者只是获得不一样的数据展现形式。这个功能特性并无作什么,只是对列的展现。但总会是有用的。

console.table() 只有处理最多1000行的数据的能力,因此它可能并不适用于全部的数据集合。

console.assert()

一个常常被忽视的实用的函数,assert() 在第一个参数是 falsey 时和 log() 同样。当第一个参数为真值时也什么都不作。

这个在你须要循环(或者不一样的函数调用)而且只有一个要显示特殊的行为的场景下特别有用。本质上和这个是同样的。

if (object.whatever === 'value') {
  console.log(object);
}
复制代码

澄清一下,当我说「同样」的时候,我本应该说是作相反的事。因此你须要变换一下场合。

因此,假设咱们上面的值在时间戳里有一个 null 或者 0,这会破坏咱们代码日期格式。

console.assert(tx.timestamp, tx);
复制代码

当和任何有效的事物对象一块儿使用时会跳过。可是有一个触发了咱们的日志记录,由于时间戳在 0 和 null 时为假值

有时咱们想要更加复杂的场景。举个例子,咱们看到了关于用户 WAL0412 的数据问题而且想要只展现来自它们的事务。这将会是一个很是简便的方案。

console.assert(tx.buyer === 'WAL0412', tx);
复制代码

看起来正确,可是并不奏效。牢记,场景必须是为否认态,我门想要的是断言,而不是过滤

console.assert(tx.buyer !== 'WAL0412', tx);
复制代码

咱们想作的就是这样。在那种状况下,全部不是 WAL0412 号顾客的事务都为真值,只留下那些符合的事务。或者,也不彻底是。

诸如此类,console.assert() 并非一直都很管用。可是在特定的场景下会是最优雅的的解决方法。

console.count()

另一个合适的用法是,将console做为一个计数器使用。

for(let i = 0; i < 10000; i++) {
  if(i % 2) {
    console.count('odds');
  }
  if(!(i % 5)) {
    console.count('multiplesOfFive');
  }
  if(isPrime(i)) {
    console.count('prime');
  }
}
复制代码

这不是一段有用的代码,而且有点抽象。我也不打算去证实 isPrime 函数,只假设能够运行。

咱们将获得应该是这样的列表

odds: 1
odds: 2
prime: 1
odds: 3
multiplesOfFive: 1
prime: 2
odds: 4
prime: 3
odds: 5
multiplesOfFive: 2
...
复制代码

以及剩下的。在你只想列出索引,或者想保留一次(或屡次)计数的状况下很是有用。

你也能像那样使用 console.count(),不须要参数。使用 default 调用。

这还有关联函数 console.countReset(),若是你但愿重置计数器可使用它。

console.trace()

这在简单的数据中演示更加困难。在你试图找出有问题的内部类或者库的调用这一块是它最擅长。

举个例子,这儿可能有 12 个不一样的组件正在调用一个服务,可是其中一个没有正确配置依赖。

export default class CupcakeService {
    
  constructor(dataLib) {
    this.dataLib = dataLib;
    if(typeof dataLib !== 'object') {
      console.log(dataLib);
      console.trace();
    }
  }
  ...
}
复制代码

这里单独使用 console.log() 咱们只能知道执行了哪个基础库,并不知道执行的具体位置。可是,堆栈轨迹会清楚的告诉咱们问题在于 Dashboard.js,咱们从中发现 new CupcakeService(false) 是形成出错的罪魁祸首。

console.time()

console.time() 是专门用于监测操做的时间开销的函数,也是监测 JavaScript 细微时间的更好的方式。

function slowFunction(number) {
  var functionTimerStart = new Date().getTime();
  // something slow or complex with the numbers. 
  // Factorials, or whatever.
  var functionTime = new Date().getTime() - functionTimerStart;
  console.log(`Function time: ${ functionTime }`);
}
var start = new Date().getTime();

for (i = 0; i < 100000; ++i) {
  slowFunction(i);
}

var time = new Date().getTime() - start;
console.log(`Execution time: ${ time }`);
复制代码

这是一个过期的方法。我指的一样还有上面的 console.log。大多数人没有意识到这里你本可使用模版字符串和插值法。它时不时的会帮助到你。

那么让咱们更新一下上面的代码。

const slowFunction = number =>  {
  console.time('slowFunction');
  // something slow or complex with the numbers. 
  // Factorials, or whatever.
  console.timeEnd('slowFunction');
}
console.time();

for (i = 0; i < 100000; ++i) {
  slowFunction(i);
}
console.timeEnd();
复制代码

我如今不须要去作任何算术或者设置临时变量。

console.group()

现在咱们可能在大多数 console 中要输出高级和复杂的东西。分组可让你概括这些。尤为是让你能使用嵌套。它擅长展现代码中存在的结构关系。

// this is the global scope
let number = 1;
console.group('OutsideLoop');
console.log(number);
console.group('Loop');
for (let i = 0; i < 5; i++) {
  number = i + number;
  console.log(number);
}
console.groupEnd();
console.log(number);
console.groupEnd();
console.log('All done now');
复制代码

这又有一点难以理解。你能够看看这里的输出。

这并非颇有用,可是你能看到其中一些是如何组合的。

class MyClass {
  constructor(dataAccess) {
    console.group('Constructor');
    console.log('Constructor executed');
    console.assert(typeof dataAccess === 'object', 
      'Potentially incorrect dataAccess object');
    this.initializeEvents();
    console.groupEnd();
  }
  initializeEvents() {
    console.group('events');
    console.log('Initialising events');
    console.groupEnd();
  }
}
let myClass = new MyClass(false);
复制代码

不少工做和代码在调试信息上可能并非那么有用。可是仍然是一个有意思的办法,同时你能够看到它使你打印的上下文是多么的清晰。

关于这个,还有最后一点须要说明,那就是 console.groupCollapsed。功能上和 console.group 同样,可是分组块一开始是折叠的。它没有获得很好的支持,可是若是你有一个无心义的庞大的分组并想默认隐藏它,能够试试这个。

结语

这里真的没有过多的总结。在你可能只想获得比 console.log(pet) 的信息更多一点,而且不太须要调试器的时候,上面这些工具均可能帮到你。

也许最有用的是 console.table,可是其余方法也都有其适用的场景。在咱们想要调试一些东西时,我热衷于使用 console.assert,但那也只在某种特殊状况下。

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索