前言

前几天在看青柠起始页的时候偶然间看到它的控制台居然可以这样 👊

于是就萌生了学一波 console 方法的念头,今天正好有时间就来把这几天的学习成果记录一下 😶

console 的基本用法

console.log("最常见用法\n换行");

console.error("输出错误信息 会以红色显示");

console.warn("打印警告信息 会以黄色显示");

console.info("打印一般信息");

// console.clear();//清空上面的console显示

//进阶用法
//console.assert(bool,”info”) 如果bool为false 打印出info 否则不打印
console.assert(false, "判断为false才显示的信息");
//传入的对象或数组以表格方式显示
console.table([["Anzhiyu", "Chen"], ["好"]]);
//打印 调用链 fn2()调用fn1(),fn1()调用fn()
function fn() {
  console.trace();
}
function fn1() {
  fn();
}
function fn2() {
  fn1();
}
fn2();

//格式化输出
/*
      console.log支持的格式标志有:
      %s       占位符
      %d 或 %i    整数
      %f       浮点数
      %o%O     object对象
      %c       css样式
    */

console.log("%d + %d = %d", 1, 2, 3);
//%o%O打印dom节点时就不一样
console.log("%o", document.body);
console.log("%O", document.body);
// %c 后面的内容,增加css样式
//附:console.log输出的超链接会被自动识别并加上灰色字体颜色和下划线的样式,而这个无法用%c覆盖
console.log("123 %c 456", "font-size:36px;color:red;");
console.log("123 %c 4 https://anzhiy.cn 56 %c 789", "font-size:20px;color:#3b70fc;", "font-size:12px;color:#000");
//利用css样式加载图片
//没法直接设置width和height样式,line-height图片高度,再调padding
console.log(
  "%c ",
  'background-image:url("https://cdn.jsdelivr.net/gh/waterchen520/cdn2@latest/anzhiy.cn.jpg");background-size:120% 120%;background-repeat:no-repeat;background-position:center center;line-height:60px;padding:30px 120px;'
);
//高级用法
//计时,单位毫秒
console.time();
for (var i = 0; i < 100000; i++) {
  var j = i * i;
}
console.timeEnd();
//统计代码或函数被调用了多少次
var fn_ = function () {
  console.count("hello world");
};
for (var i = 0; i < 5; i++) {
  fn_();
}
//查看内存使用情况,是属性,不带括号
//console.memory;
//在浏览器开发者工具中使用
//分组输出,可嵌套
console.group("分组1");
console.log("语文");
console.log("数学");
console.group("其他科目");
console.log("化学");
console.log("地理");
console.log("历史");
console.groupEnd("其他科目");

展开上面代码运行可以得到

注意以上某些方法某些浏览器IE:没错就是我不支持

console 详解

让我们来看看谷歌浏览器提供的 console 方法的 API https://developer.chrome.com/docs/devtools/console/

我们来重写 console,发现它里面有很多方法

console.assert(expression, object)

在被评估的表达式为 false 时向控制台写入一个错误。

function greaterThan(a, b) {
  console.assert(a > b, { message: "a is not greater than b", a: a, b: b });
}
greaterThan(5, 6);

console.clear()

清除控制台。

console.clear();1

如果已启用 Preserve log 复选框,console.clear() 将停用。 不过,在控制台处于聚焦状态时,按 clear console 按钮或者输入 Ctrl+L 快捷键仍然有效。

console.count(label)

写入在同一行使用相同标签调用 count() 的次数。

function login(name) {
  console.count(name + ' logged in');
}

console.debug(object [, object, …])

console.log() 作用相同。

console.dir(object)

输出以 JavaScript 形式表示的指定对象。如果正在记录的对象是 HTML 元素,将输出其以 DOM 形式表示的属性,如下所示:

console.dir(document.body);

比 console.log 更加详细

console.dirxml(object)

如果可以,输出 object 子级元素的 XML 表示形式,否则输出其 JavaScript 表示形式。 在 HTML 和 XML 元素上调用 console.dirxml() 等同于调用 console.log()

console.dirxml(document);

console.error(object [, object, …])

输出一条类似于 console.log() 的消息,将消息设置成错误样式,并在调用此方法的地方包含一个堆叠追踪。

console.error('error: name is undefined');

console.group(object[, object, …])

启动一个带有可选标题的新日志组。以可视化方式将在 console.group() 后、console.groupEnd() 前发生的所有控制台输出组合在一起。

function name(obj) {
  console.group("name");
  console.log("first: ", obj.first);
  console.log("middle: ", obj.middle);
  console.log("last: ", obj.last);
  console.groupEnd();
}

name({ first: "Wile", middle: "E", last: "Coyote" });

您还可以嵌套组:

function name(obj) {
  console.group("name");
  console.log("first: ", obj.first);
  console.log("middle: ", obj.middle);
  console.log("last: ", obj.last);
  console.groupEnd();
}

function doStuff() {
  console.group("doStuff()");
  name({ first: "Wile", middle: "E", last: "coyote" });
  console.groupEnd();
}

doStuff();

console.groupCollapsed(object[, object, …])

创建一个初始处于折叠状态而不是打开状态的新日志组。

console.groupCollapsed("status");
console.log("peekaboo, you can't see me");
console.groupEnd();

console.groupEnd()

关闭日志组。相关示例请参阅 console.group

console.info(object [, object, …])

输出一条类似 console.log() 的消息,但同时在输出旁显示一个图标(带白色“i”的蓝色圆圈)。

console.log(object [, object, …])

在控制台中显示一条消息。将一个或多个对象传递到此方法。每个对象都会进行评估并级联到一个由空格分隔的字符串中。

console.log("Hello, Logs!");

格式说明符

您传递的第一个对象可以包含一个或多个格式说明符。格式说明符由百分号 (%) 与紧跟其后面的一个字母组成,字母指示要应用的格式。

console.profile([label])

启动一个带有可选标签的 JavaScript CPU 配置文件。要完成配置文件,请调用 console.profileEnd()。 每一个配置文件都会添加到 Profiles 面板中。

function processPixels() {
  console.profile("processPixels()");
  // later, after processing pixels
  console.profileEnd();
}

console.profileEnd()

停止当前的 JavaScript CPU 分析会话(如果正在进行此会话),并将报告输出到 Profiles 面板中。

console.time(label)

启动一个具有关联标签的新计时器。使用相同标签调用 console.timeEnd() 时,定时器将停止,经过的时间将显示在控制台中。计时器值精确到亚毫秒。传递到 time()timeEnd() 的字符串必须匹配,否则计时器不会结束。

console.time("Array initialize");
var array = new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
  array[i] = new Object();
}
console.timeEnd("Array initialize");

console.timeEnd(label)

停止当前的计时器(如果正在运行一个计时器),并将计时器标签和经过的时间输出到控制台。

console.timeStamp([label])

在录制会话期间向 Timeline 添加一个事件。

console.timeStamp("check out this custom timestamp thanks to console.timeStamp()!");

console.trace(object)

从调用此方法的位置输出一个堆叠追踪。

console.trace();

console.warn(object [, object, …])

输出一条类似 console.log() 的消息,但同时在记录的消息旁显示一个黄色警告图标。

console.warn("user limit reached!");

重写简单的 console 方法

我们常用的有 console.log、console.info、console.group、console.warn、console.error、console.profile、console.time,现在我们来试着重写 console.log、console.info、console.group、console.warn、console.error 这几个常用的,其他的类似但比较复杂。

第一步,搭一个结构,覆盖浏览器(chrome\ie)提供的 console 功能,这样直接引用此 JS 文件即可保证浏览器(主要是 IE)中不出错:

var console = {
  assert: function () {},
  clear: function () {},
  count: function () {},
  debug: function () {},
  dir: function () {},
  dirxml: function () {},
  error: function () {},
  exception: function () {},
  group: function (name) {},
  groupCollapsed: function () {},
  groupEnd: function () {},
  info: function () {},
  log: function () {},
  memoryProfile: function () {},
  memoryProfileEnd: function () {},
  profile: function () {},
  profileEnd: function () {},
  table: function () {},
  time: function () {},
  timeEnd: function () {},
  timeStamp: function () {},
  trace: function () {},
  warn: function () {},
};

第二步,实现 console.log 方法。在所实现的几个方法中这个是最复杂的。

从 chrome 的 API 中我们可以看到,console.log 不仅仅可以输出信息,还提供了类似 string.Format 的功能,原文地址:https://developer.chrome.com/docs/devtools/console/api/

Here is the complete set of patterns that you may use for string substitution:

PatternType
%sString
%d, %iInteger (numeric formatting is not yet supported)
%fFloating point number (numeric formatting is not yet supported)
%oObject hyperlink
%cStyle formatting

其中的%c 比较特殊,是给输出添加样式的,比如我们在 Chrome 中这样写:

console.log("%cTest output", "color:white; background-color:blue");

运行后的结果是这样的:

这里%c 也可以跟 %s、%d 等混用。

所以,在代码中我直接用 replace 进行替换,由于 JS 中的 replace 默认只替换第一个匹配项,这里刚好,代码如下:

var args = Array.prototype.slice.call(arguments);
if (args.length > 1) {
  var i = 1,
    hasstyle = false;
  if (args[0].indexOf("%c") == 0) {
    args[0] = args[0].replace(/%c/, "");
    i = 2;
    hasstyle = true;
  }
  for (; i < args.length; i++) {
    if (/%s|%d|%i|%o/.test(args[0])) {
      args[0] = args[0].replace(/%s|%d|%i|%o/, args[i]);
    } else {
      break;
    }
  }
  if (i < args.length) {
    args[0] = args[0] + " " + args.slice(i).join(" ");
  }
  if (hasstyle) {
    consoleHelper.showlog(args[0], args[1]);
  } else {
    consoleHelper.showlog(args[0]);
  }
} else if (args.length == 1) {
  if (arguments[0] instanceof Array) {
    consoleHelper.showlog("[" + args[0] + "]");
  } else if (arguments[0] instanceof Function) {
    consoleHelper.showlog(args[0], null, "console_log_function");
  } else {
    consoleHelper.showlog(args[0]);
  }
} else {
  consoleHelper.showlog("");
}

由于 console.log 可以接受多个参数,且个数不确定,所以这里直接没有写形参。对于%c 虽然 Chrome 中写在中间也是有效的,这里为了简单直接只对写在开头的有效。代码中先把参数转换为数组,然后对数组进行分情况处理。

当参数个数大于 1 时,对后面的参数用 replace 进行替换,然后把剩下的参数连接(join)起来进行输出。

当参数个数为 1 时,还要分两种情况,一是数组,二是方法。对于数组,按 Chrome 中的格式,在两端加中括号,对于函数,把字的颜色变为绿色

当参数个数为 0 时,直接输出空字符串

后面的 consoleHelper.showlog 是为了输出方便另外写的一个方法,在这个方法中把各种调试信息的结果显示在页面上的一个 div(如果存在)中。

其他几个方法的思路跟这个差不多,只是样式不同,功能比这个简单,直接把参数连接起来输出即可。

整个 console 类代码如下:

var console = {
  assert: function () {},
  clear: function () {},
  count: function () {},
  debug: function () {},
  dir: function () {},
  dirxml: function () {},
  error: function () {
    var args = Array.prototype.slice.call(arguments);
    consoleHelper.showerror(args.join(" "));
  },
  exception: function () {},
  group: function (name) {
    consoleHelper.showgroup(name);
  },
  groupCollapsed: function () {},
  groupEnd: function () {},
  info: function () {
    var args = Array.prototype.slice.call(arguments);
    if (args.length == 1) {
      if (arguments[0] instanceof Array) {
        consoleHelper.showinfo("[" + args[0] + "]");
      } else if (arguments[0] instanceof Function) {
        consoleHelper.showinfo(args[0], "console_log_function");
      } else {
        consoleHelper.showinfo(args[0]);
      }
    } else {
      consoleHelper.showinfo(args.join(" "));
    }
  },
  log: function () {
    var args = Array.prototype.slice.call(arguments);
    if (args.length > 1) {
      var i = 1,
        hasstyle = false;
      if (args[0].indexOf("%c") == 0) {
        args[0] = args[0].replace(/%c/, "");
        i = 2;
        hasstyle = true;
      }
      for (; i < args.length; i++) {
        if (/%s|%d|%i|%o/.test(args[0])) {
          args[0] = args[0].replace(/%s|%d|%i|%o/, args[i]);
        } else {
          break;
        }
      }
      if (i < args.length) {
        args[0] = args[0] + " " + args.slice(i).join(" ");
      }
      if (hasstyle) {
        consoleHelper.showlog(args[0], args[1]);
      } else {
        consoleHelper.showlog(args[0]);
      }
    } else if (args.length == 1) {
      if (arguments[0] instanceof Array) {
        consoleHelper.showlog("[" + args[0] + "]");
      } else if (arguments[0] instanceof Function) {
        consoleHelper.showlog(args[0], null, "console_log_function");
      } else {
        consoleHelper.showlog(args[0]);
      }
    } else {
      consoleHelper.showlog("");
    }
  },
  memoryProfile: function () {},
  memoryProfileEnd: function () {},
  profile: function () {},
  profileEnd: function () {},
  table: function () {},
  time: function () {},
  timeEnd: function () {},
  timeStamp: function () {},
  trace: function () {},
  warn: function () {
    var args = Array.prototype.slice.call(arguments);
    if (args.length == 1) {
      if (arguments[0] instanceof Array) {
        consoleHelper.showwarn("[" + args[0] + "]");
      } else if (arguments[0] instanceof Function) {
        consoleHelper.showwarn(args[0], "console_log_function");
      } else {
        consoleHelper.showwarn(args[0]);
      }
    } else {
      consoleHelper.showwarn(args.join(" "));
    }
  },
};

consoleHelper 代码如下:

var consoleHelper = {
  showlog: function (val, style, cla) {
    if (cla) {
      cla = "console_log " + cla;
    } else {
      cla = "console_log";
    }
    this.show(val, style, cla);
  },
  showinfo: function (val, cla) {
    if (cla) {
      cla = "console_info " + cla;
    } else {
      cla = "console_info";
    }
    this.show(val, null, cla);
  },
  showwarn: function (val, cla) {
    if (cla) {
      cla = "console_warn " + cla;
    } else {
      cla = "console_warn";
    }
    this.show(val, null, cla);
  },
  showerror: function (val) {
    this.show(val, null, "console_error");
  },
  showgroup: function (val) {
    if (!val) {
      val = "";
    }
    this.show(val + ":", null, "console_group");
  },
  show: function (val, style, cla) {
    if (document.getElementById("showconsole")) {
      var div = document.createElement("div");
      if (div.setAttribute) {
        if (style) {
          div.setAttribute("style", style);
        }
      } else {
        if (style) {
          div = document.createElement("<div style=" + style + ">");
        }
      }
      if (cla) {
        div.className = cla;
      }
      var oText = document.createTextNode(val);
      div.appendChild(oText);
      document.getElementById("showconsole").appendChild(div);
    }
  },
};

注:如果想在页面中看到调试信息,直接在页面上添加一个id 为 showconsole 的隐藏的div即可。

样式(尽量跟 Chrome 保持一致):

.console_log {
  border: 1px solid #ccc;
  color: #333;
  padding: 0px 5px;
  min-height: 24px;
  line-height: 24px;
  margin-bottom: -1px;
}
.console_info {
  border: 1px solid #ccc;
  color: #333;
  padding: 0px 5px;
  min-height: 24px;
  line-height: 24px;
  margin-bottom: -1px;
  background: url("这里是info方法的小图标") no-repeat scroll 0 1px #ebf5ff;
  padding-left: 30px;
}
.console_warn {
  border: 1px solid #ccc;
  color: #333;
  padding: 0px 5px;
  min-height: 24px;
  line-height: 24px;
  margin-bottom: -1px;
  background: url("这里是warn方法的小图标") no-repeat scroll 0 1px #ffffc8;
  padding-left: 30px;
}
.console_error {
  border: 1px solid #ccc;
  color: #ff0000;
  padding: 0px 5px;
  min-height: 24px;
  line-height: 24px;
  margin-bottom: -1px;
  background: url("这里是error方法的小图标") no-repeat scroll 0 1px #ffebeb;
  padding-left: 30px;
}
.console_group {
  margin-top: 20px;
  font-size: 16px;
  font-weight: bolder;
}
.console_log_function {
  color: green;
}

这里为了演示方便,三个小图标直接预留了位置,大家用时可以换成图片地址。

代码实现案例

如果只需要一个简单的,类似我博客里的这种,你只需要写一个 js

下面是本博客控制台的 js 源码

var now1 = new Date();

function createtime1() {
  var grt = new Date("04/01/2021 00:00:00"); //此处修改你的建站时间或者网站上线时间
  now1.setTime(now1.getTime() + 250);
  var days = (now1 - grt) / 1000 / 60 / 60 / 24;
  var dnum = Math.floor(days);

  var ascll = [
    `欢迎来到Anzhiyu\`Blog!`,
    `生活明朗, 万物可爱`,
    `

  ██╗   ██╗██╗ ██████╗ ██╗     ███████╗████████╗
  ██║   ██║██║██╔═══██╗██║     ██╔════╝╚══██╔══╝
  ██║   ██║██║██║   ██║██║     █████╗     ██║   
  ╚██╗ ██╔╝██║██║   ██║██║     ██╔══╝     ██║   
   ╚████╔╝ ██║╚██████╔╝███████╗███████╗   ██║   
    ╚═══╝  ╚═╝ ╚═════╝ ╚══════╝╚══════╝   ╚═╝   
                                              
`,
    "Anzhiyu`Blog 已上线",
    dnum,
    "天",
    "©2021 By Anzhiyu",
  ];

  setTimeout(
    console.log.bind(
      console,
      `\n%c${ascll[0]} %c ${ascll[1]} %c ${ascll[2]} %c${ascll[3]}%c ${ascll[4]}%c ${ascll[5]}\n\n%c ${ascll[6]}\n`,
      "color:#3b70fc",
      "",
      "color:#3b70fc",
      "color:#3b70fc",
      "",
      "color:#3b70fc",
      ""
    )
  );
}

createtime1();

function createtime2() {
  var ascll2 = [`NCC2-036`, `调用前置摄像头拍照成功,识别为【小笨蛋】.`, `Photo captured: `, `  `];

  setTimeout(
    console.log.bind(
      console,
      `%c ${ascll2[0]} %c ${ascll2[1]} %c \n${ascll2[2]} %c\n${ascll2[3]}\n`,
      "color:white; background-color:#4fd953",
      "",
      "",
      'background:url("https://unpkg.zhimg.com/anzhiyu-assets@latest/image/common/tinggge.gif") no-repeat;font-size:450%'
    )
  );

  setTimeout(console.log.bind(console, "%c WELCOME %c 你好,小笨蛋.", "color:white; background-color:#4f90d9", ""));

  setTimeout(
    console.warn.bind(
      console,
      "%c ⚡ Powered by Anzhiyu %c 你正在访问 Anzhiyu 的博客.",
      "color:white; background-color:#f0ad4e",
      ""
    )
  );

  setTimeout(console.log.bind(console, "%c W23-12 %c 你已打开控制台.", "color:white; background-color:#4f90d9", ""));
  setTimeout(
    console.warn.bind(console, "%c S013-782 %c 你现在正处于监控中.", "color:white; background-color:#d9534f", "")
  );
}
createtime2();

console.log = function () {};

写下这篇博客的时候 📌,已经忘记参考地址是哪里了,算是一个汇总吧,参考地址百度

啦啦啦~

我一直想从你的窗子里看月亮。💡~