小曹同学的百草园
首页
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

小曹同学

一个普通的前端开发
首页
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • axios工具函数

    • ⭐️前言
      • isBuffer判断buffer
      • isFormData判断FormData
      • isObject判断对象
      • isPlainObject 判断纯对象
      • isFile判断文件类型
      • isBlob 判断Blob
      • isStream流
      • isURLSearchParams 判断URLSearchParams[^5]
      • trim去除首尾空格
      • forEach遍历对象或数组
      • stripBOM删除UTF-8编码中BOM
    • 📦总结
      • 📃参考资料
      • 源码学习笔记
      小曹同学
      2021-12-22
      目录

      axios工具函数

      # ⭐️前言

      这次仍然是一份关于工具函数的源码阅读笔记,希望能对您有所帮助。

      # isBuffer判断buffer

      # 关于Node.js Buffer(缓冲区)

      JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。

      但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

      # 💡源码与解析:
      /**
       * Determine if a value is a Buffer
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is a Buffer, otherwise false
       */
      function isBuffer(val) {
        return val !== null && 
             !isUndefined(val) &&  // 判断val不为undefined
            val.constructor !== null && // 判断val存在constructor构造函数,因为Buffer本身是一个类
            !isUndefined(val.constructor)&& // 判断constructor是否有定义
            typeof val.constructor.isBuffer === 'function' &&       val.constructor.isBuffer(val);// 在上述一系列操作后基本可以确定val是一个类,最后通过 Buffer类的isBuffer方法来判断是否为buffer类即可
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

      # isFormData判断FormData

      关于instanceof运算符的知识,在vue3工具函数 (opens new window)中已经详细讲述,此处不做赘述

      # 💡源码:
      /**
       * Determine if a value is a FormData
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is an FormData, otherwise false
       */
      function isFormData(val) {
        return (typeof FormData !== 'undefined') && (val instanceof FormData);
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      # isObject判断对象

      由于判断isObject的方法是通过typeof来实现的,其中typeof null与typeof Object输出的结果都是Object。所以需要先检测传入的参数是否为null保证函数判断的准确性

      关于typeof null 与 typeof Object为什么结果都是Object可参考这篇文章:为什么typeof null的结果是Object? (opens new window)[^1]

      # isPlainObject 判断纯对象

      纯对象: 用{}或new Object()创建的对象。

      # 💡源码解析:

      # 源码
      /**
       * Determine if a value is a plain Object
       *
       * @param {Object} val The value to test
       * @return {boolean} True if value is a plain Object, otherwise false
       */
      function isPlainObject(val) {
        if (toString.call(val) !== '[object Object]') {
          return false;
        }
      
        var prototype = Object.getPrototypeOf(val);
        return prototype === null || prototype === Object.prototype;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # 涉及知识点
      • [x] Object.getPrototypeOf(Object):返回指定对象的原型(内部[[Prototype]]属性的值)[^2]

        这里涉及到的是通过Object.getPrototypeOf()来判断被检测对象的原型是否为Object,并且以此来作为是否为纯函数的依据之一

      • 纯对象示例

      纯对象示例

      • 非纯对象示例
      • 非纯对象示例

      # isFile判断文件类型

      # 💡源码解析:

      通过toString方法转换获取类型字符串[object File]来验证是否为文件类型

      /**
       * Determine if a value is a File
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is a File, otherwise false
       */
      function isFile(val) {
        return toString.call(val) === '[object File]';
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      # isBlob 判断Blob

      Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取。

      更多关于blob的资料可以参考这篇文章:你不知道的 Blob[^3]

      # 💡源码:

      /**
       * Determine if a value is a Blob
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is a Blob, otherwise false
       */
      function isBlob(val) {
        return toString.call(val) === '[object Blob]';
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      ==后面关于判断是否为函数,是否为date等检验函数原理都相同,此处不多赘述==

      # isStream流

      概念:流是为 Node.js 应用程序提供动力的基本概念之一。是一种以高效的方式处理读/写文件、网络通信、或任何类型的端到端的信息交换.[^4]

      所以判断是否为流,需要首先判断是否为Object,第二需要判断其中的pie方法

      # 💡源码:

      /**
       * Determine if a value is a Stream
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is a Stream, otherwise false
       */
      function isStream(val) {
          // isObject 与 isFunction是上面所提到的判断是否为对象与函数的工具函数
        return isObject(val) && isFunction(val.pipe);
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10

      # isURLSearchParams 判断URLSearchParams[^5]

      URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串。

      通过 new URLSearchParams()可以返回一个 URLSearchParams对象。

      更多URLSearchParams相关内容参考MDN中的文档[^5]

      1. 先判断此环境中拥有类URLSearchParams
      2. 然后判断val是URLSearchParams对象

      image-20211222160039084

      /**
       * Determine if a value is a URLSearchParams object
       *
       * @param {Object} val The value to test
       * @returns {boolean} True if value is a URLSearchParams object, otherwise false
       */
      function isURLSearchParams(val) {
        return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      # trim去除首尾空格

      单独重新做一个trim函数来去除首尾空格是考虑到了trim方法不存在的情况下,使用正则来确保功能

      通过匹配以开始的空格或者以结尾的空格然后利用string.replace()方法替换掉

      # 正则图解

      image-20211222160940302

      # 💡源码

      /**
       * Trim excess whitespace off the beginning and end of a string
       *
       * @param {String} str The String to trim
       * @returns {String} The String freed of excess whitespace
       */
      function trim(str) {
        return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      # forEach遍历对象或数组

      将数组的遍历与对象的遍历进行了整合,同时也处理了可能传入的参数并非对象、数组的情况

      # 示例

      image-20211222163156064

      # 💡源码解析:

      /**
       * Iterate over an Array or an Object invoking a function for each item.
       * 用一个函数迭代数组或者对象 iterate:迭代 invoking:调用
       * If `obj` is an Array callback will be called passing
       * the value, index, and complete array for each item.
       * 如果参数`obj`为一个数组回调将会调用value,index和整个数组 complete:完整的
       * If 'obj' is an Object callback will be called passing
       * the value, key, and complete object for each property.
       * 如果参数`obj`为一个对象,回调将会调用value,key和整个对象
       * @param {Object|Array} obj The object to iterate
       * @param {Function} fn The callback to invoke for each item
       */
      function forEach(obj, fn) {
        // Don't bother if no value provided
        // 如果参数不存在则不需要处理直接返回
        if (obj === null || typeof obj === 'undefined') {
          return;
        }
      
        // Force an array if not already something iterable
        // 如果参数不是一个对象`object`则直接强制转换成数组。防止使用者因为传入各种奇怪的参数导致函数不能使用
        if (typeof obj !== 'object') {
          /*eslint no-param-reassign:0*/
          obj = [obj];
        }
      
        if (isArray(obj)) {
          // Iterate over array values
          for (var i = 0, l = obj.length; i < l; i++) {
            fn.call(null, obj[i], i, obj);
          }
        } else {
          // Iterate over object keys
          for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
              fn.call(null, obj[key], key, obj);
            }
          }
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40

      # stripBOM删除UTF-8编码中BOM

      # 关于BOM[^6]

      所谓 BOM,全称是Byte Order Mark,它是一个Unicode字符,通常出现在文本的开头,用来标识字节序。UTF-8主要的优点是可以兼容ASCII,但如果使用BOM的话,这个好处就荡然无存了。

      关于为什么BOM与UTF-8不能共存,可参考知乎的这篇文章「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?网页代码一般使用哪个? (opens new window)[^7]

      Bytes representing the BOM.

      # 💡源码

      /**
       * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
       *
       * @param {string} content with BOM
       * @return {string} content value without BOM
       */
      function stripBOM(content) {
        if (content.charCodeAt(0) === 0xFEFF) {
          content = content.slice(1);
        }
        return content;
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      # 📦总结

      在通过这几篇关于工具函数以及工具包的一个详细了解和阅读之后,我发现在编写工具函数时,最好遵循以下几点规则:

      • 永远不要相信使用者会怎么样按照你的想法去使用你的工具,而是要做好一切的尽可能想到的边缘情况来保证就算使用者第一次使用胡乱的使用你的工具时,你的工具仍然能够安全完整的按照你的想法运行和得出结果。
      • 做好工具函数的注释,各种参数的详细解释。以方便后来人使用工具函数时,能够更加了解你的工具函数的作用
      • 一个工具函数只处理一件事。即使不同的工具函数里的代码只是有细微的不同,具体参考各类的对象,方法等检测函数。

      今天一天内产出阅读了两个源码笔记,接下来需要好好地沉淀一下,不能过于急躁的学习和产出。所以接下来的几天打算好好地再复习复习以前的笔记。

      第五篇笔记:总用时 3小时左右

      # 📃参考资料

      [^1]:阳光。 为什么typeof null 的结果是Object? (opens new window) 2019年7月23日 [^2]:MDN Web Docs Object.getPrototypeOf(Object)方法 (opens new window) [^3]:阿宝哥 你不知道的Blob (opens new window) [^4]:nodejs 中文文档 Node.js 流 (opens new window) [^5]:MDN Web Docs URLSearchParams (opens new window) [^6]:W3C The byte-order mark (BOM) in HTML (opens new window) [^7]:梁海 「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?网页代码一般使用哪个? (opens new window)

      编辑 (opens new window)
      上次更新: 2022/02/21, 05:57:00
      最近更新
      01
      优雅代码书写之道
      06-07
      02
      图片懒加载
      05-05
      03
      项目部署
      04-16
      更多文章>
      Theme by Vdoing
      • 跟随系统
      • 浅色模式
      • 深色模式
      • 阅读模式