夜听城嚣 夜听城嚣
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏

dwfrost

前端界的小学生
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏
  • 读书笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

  • 项目实践

  • 框架应用

  • 前端一览
  • 专题分享
frost
2022-11-27

重写console.log

完整代码见底部

阅读开源库的时候,发现别人会设计自己内置的 log 方法,比如 vue-cli 工具会有自己的 logger,这样就可以定制 console.log,形成自己的风格。

基于此,我想到了两个功能点,并查找了相关博客,形成了这篇笔记。功能需求是:

  • 在每次 log 时,输出当前时间,这样可以比较前后 log 之间的时间差别
  • 时间 log 标记为特殊样式,以示区分

但是,我不想要改动原来项目中已有的 log,即不需要调用方额外引入一个工具函数,并调用。答案是在 console.log 使用前,劫持 console.log,时间及其样式均在此完成。

  1. 劫持 console.log

    一般认为是重写原型,这里不是,而是直接重写该方法。通过调用自执行函数来完成,并在该函数中做处理,如下:

    console.log = (function(logFunc) {
      return function() {
        logFunc.call(console, 'this is my log', ...arguments)
      }
    })(console.log)
    
    1
    2
    3
    4
    5

    输出为

    console.log(123) // this is my log 123
    
    1
  2. 加上时间

    由于自执行函数返回了函数,所以内部的函数不会立即执行,在这里可以获取当前时间。

    console.log = (function(logFunc) {
      return function() {
        const now = new Date()
        const time = now.toLocaleString() + '.' + now.getMilliseconds()
        logFunc.call(console, time, ...arguments)
      }
    })(console.log)
    // 2022/11/27 16:11:05.285 123
    
    1
    2
    3
    4
    5
    6
    7
    8

    看上去有点长,并且我们输出时间一般是为了比较前后 log 的时间(比如页面进入到页面离开,或者接口请求到接口返回),所以这里日期可以去掉。

    -     const time = now.toLocaleString() + '.' + now.getMilliseconds()
    +		  const time = now.toLocaleTimeString() + '.' + now.getMilliseconds()
      // 16:14:04.708 123
    
    1
    2
    3

    在实践中发现,有时候毫秒的位数不一样,看起来不整齐。

    16:17:38.95 123
    16:17:38.397 123
    
    1
    2

    做下优化:

    const now = new Date()
    let ms = now.getMilliseconds() + ''
    let len = ms.length
    while (len < 3) {
      ms = '0' + ms
      len++
    }
    const time = now.toLocaleTimeString() + '.' + ms
    
    1
    2
    3
    4
    5
    6
    7
    8

    看起来就整齐了,切口一致。

    16:19:43.036 123
    16:19:43.335 123
    
    1
    2
  3. 深拷贝

    前端调试时经常会打印前后的对象,比较他们的值和内部属性,但经常发现要么由于页面切换等原因,该变量早就销毁,要么前后该变量内的值一模一样。是因为 js 引用指向同 个地址,前后输出的实际是同一个对象,这里可以坐下深拷贝来规避。举例:

    const obj = {
      a: 1,
    }
    console.log(obj) // obj.a = 2
    obj.a = 2
    console.log(obj) // obj.a = 2
    
    1
    2
    3
    4
    5
    6

    这里简单做下深拷贝:

    const arr = [...arguments]
    arr.forEach((item, index) => {
      if (Object.prototype.toString.call(item) === '[object Object]' || Object.prototype.toString.call(item) === '[object Array]') {
        arr[index] = JSON.parse(JSON.stringify(item))
      }
    })
    logFunc.call(console, time, ...arr)
    
    1
    2
    3
    4
    5
    6
    7

    这下就是完全不同的值了。

  4. 美化

    这里的时间和正常的 log 样式完全一样,log 多了可能会视觉疲劳,想看自己的 log 还要费一点劲,这里做下美化,以示区分。

    我们打开baidu.com的控制台,发现它就是做了美化,实际就是将 css 样式往上造。

    const style = `background:#2d8cf0; padding: 2px; border-radius: 4px;color: #fff;`
    logFunc.call(console, `%c ${time}`, style, ...arr)
    
    1
    2

    加了样式

    log1这个颜色太深了,容易吸引开发者的注意,实际上时间只是少数场景下会关注 的。换个样式。

    const style = 'color:#909399;
    
    1

    log2

    这样既不会影响到阅读,也可以很好的区分。

  5. 最后

    改造 console.log 到这里就算完成了,但是还有点不完美的地方,是原来的堆栈信息丢失了,所有的堆栈都会定位到封装的自执行函数内部,造成调试的不方便。临时的 hack 方 案是,紧接着输出该日志的堆栈信息,但这有会作为冗余,所以默认不开启。完整代码如下:

    console.log = (function(logFunc, debug = false) {
      return function() {
        const now = new Date()
        let ms = now.getMilliseconds() + ''
        let len = ms.length
        while (len < 3) {
          ms = '0' + ms
          len++
        }
        const time = now.toLocaleTimeString() + '.' + ms
    
        const arr = [...arguments]
        arr.forEach((item, index) => {
          if (Object.prototype.toString.call(item) === '[object Object]' || Object.prototype.toString.call(item) === '[object Array]') {
            arr[index] = JSON.parse(JSON.stringify(item))
          }
        })
        const style = 'color:#909399;'
        logFunc.call(console, `%c ${time}`, style, ...arr)
        debug && console.trace()
      }
    })(console.log)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    js 重写 console.log 函数 (opens new window)

    前端工具包之 log 美化 (opens new window)

上次更新: 2022/11/27, 18:23:59
最近更新
01
提交代码时修改commit消息
04-09
02
如何快速定位bug
02-20
03
云端web项目开发踩坑
08-25
更多文章>
Theme by Vdoing | Copyright © 2021-2025 dwfrost | 粤ICP备2021118995号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×