除了console.log之外,还有更多方式调试JavaScript来输出值。 看起来很明显我们没有。人们告诉我,做JavaScript应该使用浏览器的调试器,但这肯定是要看运行环境的。 但是很多时候你只想知道代码的某一部分是执行还是变量是什么,而不会看着断点消失庞大的代码类库中。尽管如此,虽然我们使用console.log,但是很多人都没有意识到控制台本身除了基本日志之外还有很多其他选项。 适当使用这些功能可以使调试更容易,更快速,更直观。console.log()在旧的console.log中有超出人期望令人惊讶的功能。 虽然大多数人将它用作console.log(obj),但您也可以执行console.log(object,otherObject,string),它会将它们全部记录下来。 有时候方便。除此之外,还有另一种格式:console.log(msg,values)。 这很像像C或PHP中的sprintf。console.log(‘I like %s but I do not like %s.’, ‘Skittles’, ‘pus’);将完全按照您的预期输出。> I like Skittles but I do not like pus.常见的占位符是%o(这是一个字母o,而不是零),它接受一个对象,%s接受一个字符串,%d是一个十进制或整数。另一个有趣的是%c, 它实际上是CSS值的占位符。console.log(‘I am a %cbutton’, ‘color: white; background-color: orange; padding: 2px 5px; border-radius: 2px’);这些值会运行到后面的任何内容上,没有“结束标记”,这有点奇怪。 但你可以将它变得像这样。它不优雅,也不是特别有用。 当然,这不是一个真正的按钮。它有用吗?Ehhhhh。console.dir()在大多数情况下,console.dir()函数非常类似于log(),尽管它看起来有点不同。向下的小箭头将显示与上面相同的确切对象详细信息,这也可以从console.log版本中看到。 当你看到元素时,事物的分歧更加剧烈,更有趣。let element = document.getElementById(‘2x-container’);这是记录输入的输出:我打开了一些元素。 这清楚地显示了DOM,我们可以浏览它。 但是console.dir(element)为我们提供了惊人的不同输出。这是一种更加客观的方式来查看元素。 有时候这就是你真正想要的东西,更像是检查元素。console.warn()可能是最明显的直接替换log(),你可以用完全相同的方式使用console.warn()。 唯一真正的区别是输出有点黄。 具体来说,输出处于警告级别而不是信息级别,因此浏览器将稍微区别对待它。 这具有使其在杂乱输出中更明显的效果。但是,有一个更大的优势。 因为输出是警告而不是信息,所以您可以过滤掉所有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.tabl(data)的输出更有帮助。可选的第二个参数是您想要的列的列表。 显然默认为所有列,但我们也可以这样做。> console.table(data, [“id”, “price”]);我们得到这个输出,只显示id和价格。 适用于过大的物体,细节基本无关。 索引列是自动创建的,并且据我所知不可以去掉。这里要注意的是这是乱序的 - 最右边的列标题上的箭头显示了原因。 我点击该列进行排序。 找到列的最大或最小,或者只是对数据进行不同的查看非常方便。 顺便说一句,该功能与显示部分列无关。 它始终可用。console.table()只能处理最多1000行,因此可能不适合所有数据集。console.assert()断言有用的函数assert() 与log() 相同,但仅在第一个参数为false的情况下。 如果第一个参数为真,它什么都不做。这对于有循环(或几个不同的函数调用)并且只有一个显示特定行为的情况特别有用。 基本上它和这样做是一样的。if (object.whatever === ‘value’) { console.log(object);}澄清的是,当我说“相同”时,做起来却是相反的。 所以你需要反转条件。因此,让我们假设上面的一个值是在时间戳中使用null或0,这会搞砸我们的代码格式化日期。console.assert(tx.timestamp, tx);当与任何有效的事务对象一起使用时,它只是跳过去。 但是false会触发我们的日志记录,因为时间戳是0或null。有时我们想要更复杂的条件。 例如,我们已经看到用户WAL0412的数据存在问题,并且只想显示来自它们的事务。 这是直观的解决方案。console.assert(tx.buyer === ‘WAL0412’, tx);这看起来正确,但不起作用。 请记住,条件必须是false…我们要断言,而不是过滤。console.assert(tx.buyer !== ‘WAL0412’, tx);这将做我们想要的。 买方不是WAL0412的任何交易在该条件下都是正确的,只留下那些。 或者……不是。像其中的一些,console.assert()并不总是特别有用。 但在特定情况下它可以是一个优雅的解决方案。console.count()另一个使用有用的功能,count只是作为一个计数器,可选择作为一个命名计数器。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: 1odds: 2prime: 1odds: 3multiplesOfFive: 1prime: 2odds: 4prime: 3odds: 5multiplesOfFive: 2…等等。 这对于您可能只是转储索引的情况很有用,或者您希望保留一个(或多个)运行计数。您也可以像这样使用console.count(),不带参数。 这样做会将其称为默认值。如果您愿意,还可以使用相关的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()会告诉我们传入的dataLib是什么,而不是在哪里。 但是,堆栈跟踪将非常清楚地告诉我们问题是Dashboard.js,我们可以看到它是新的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()现在可能是控制台输出中最复杂和最先进的区域。 group让你……好吧,分组。 特别是它可以让你嵌套东西。 它擅长的地方在于显示代码中存在的结构。// this is the global scopelet 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,但所有其他api也都有自己的作用。 我是console.assert的粉丝,因为我们想调试一些东西,但只能在特定情况下调试。