【若川视野 x 源码共读】第19期 | axios工具函数

85 阅读3分钟

前言

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

源码

在写axsios工具函数之前,大概的过了一下其源码,源码中大量的使用了箭头函数和闭包,以及函数字面量声明,对于一些初级的开发者来说,阅读起来有点儿磕绊,基础薄弱的可以试着将箭头函数还原,对比一下源码和还原的代码,学习大佬的编程方法和思维,对自己很有帮助。

kindOf 判断数据类型

const {toString} = Object.prototype;
​
const kindOf = (cache => thing => {
    const str = toString.call(thing);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
})(Object.create(null));

在此呢,我还原一下这个函数,如下

const {toString} = Object.prototype;
​
function kindCatch (cache) {
  return function (thing) {
    const str = toString.call(cache);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  }
}
​
const kindOf = kindCatch(Object.create(null));

简单说一下这个函数吧

  1. 先声明一个函数kindCatch,接收一个catche参数,作为数据缓存容器
  2. 这个函数返回的是一个函数,接收一个任意变量thing,其结果返回的是变量的数据类型
  3. 最后,得到kindOf函数,并传入初始实参Object。create(null),就是内部返回的函数

函数执行逻辑

  1. 传入变量thing,通过toString.call获得当前变量的类型[object xxxx]
  2. 然后从缓存catch里读取其类型,有直接返回,没有则将当类型存入catch
  3. 最后返回数据的类型xxxx

函数运行结果

// 此时的catch -> {}
kindOf("Axios"); // string
​
// 此时的catch -> {'[object String]': 'string'}
kindOf(314); // number
​
// 此时的catch -> {'[object String]': 'string', '[object Number]': 'number'}
kindOf(true); //boolean
​
// 此时的catch -> {'[object String]': 'string', '[object Number]': 'number', '[object Boolean]': 'boolean'}

kindOfTest 判断传入的数据类型是否为预定义的类型

const kindOfTest = (type) => {
  type = type.toLowerCase();
  return (thing) => kindOf(thing) === type
}

源码中使用kindOfTest声明了如下几个函数

// 日期类型
const isDate = kindOfTest('Date');
​
// 文件类型
const isFile = kindOfTest('File');
​
// Blob类型
const isBlob = kindOfTest('Blob');
​
// 文件列表类型
const isFileList = kindOfTest('FileList');
​
// URL搜索参数类型
const isURLSearchParams = kindOfTest('URLSearchParams');
​
// HTML表单元素
const isHTMLForm = kindOfTest('HTMLFormElement');
​
// 正则表达式
const isRegExp = kindOfTest('RegExp');

typeOfTest 判断传入的数据类型是否为预定义的类型

const typeOfTest = type => thing => typeof thing === type;

只是这个类型校验是通过typeof,需要了解typeofObject.prototype.toString的异同点。

源码中使用typeofTest声明了如下几个函数

// undefined
const isUndefined = typeOfTest('undefined');
​
// string
const isString = typeOfTest('string');
​
// function
const isFunction = typeOfTest('function');
​
// number
const isNumber = typeOfTest('number');

isObject 判断数据是否是object类型

const isObject = (thing) => thing !== null && typeof thing === 'object';

isBoolean 判断数据是否是Booleanl类型

const isBoolean = thing => thing === true || thing === false;

isPlainObject 判断数据是否是普通对象

const {getPrototypeOf} = Object;
​
const isPlainObject = (val) => {
  if (kindOf(val) !== 'object') {
    return false;
  }
​
  const prototype = getPrototypeOf(val);
  return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);
}

isFormData 判断数据是否是表单数据

const isFormData = (thing) => {
  const pattern = '[object FormData]';
  return thing && (
    (typeof FormData === 'function' && thing instanceof FormData) ||
    toString.call(thing) === pattern ||
    (isFunction(thing.toString) && thing.toString() === pattern)
  );
}

forEach 回调遍历对象的所有属性值

function forEach(obj, fn, {allOwnKeys = false} = {}) {
    
  if (obj === null || typeof obj === 'undefined') {
    return;
  }
​
  let i;
  let l;
​
  if (typeof obj !== 'object') {
    obj = [obj];
  }
​
  if (isArray(obj)) {
    for (i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
    const len = keys.length;
    let key;
​
    for (i = 0; i < len; i++) {
      key = keys[i];
      fn.call(null, obj[key], key, obj);
    }
  }
}

trim 去除首尾空格

const trim = (str) => str.trim ?
  str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');

findKey 查找对象中的key属性

function findKey(obj, key) {
  key = key.toLowerCase();
  const keys = Object.keys(obj);
  let i = keys.length;
  let _key;
  while (i-- > 0) {
    _key = keys[i];
    if (key === _key.toLowerCase()) {
      return _key;
    }
  }
  return null;
}

toCamelCase 转换为驼峰命名

const toCamelCase = str => {
  return str.toLowerCase().replace(/[_-\s]([a-z\d])(\w*)/g,
    function replacer(m, p1, p2) {
      return p1.toUpperCase() + p2;
    }
  );
};

知识拓展

Object.getOwnPropertyNames vs Object.keys

Object.getOwnPropertyNames返回的是对象所有自己的属性,而Object.keys(obj)则返回的是所有可枚举属性,也就是属性下的enumerable: true

URLSearchParams

URLSearchParams接口定义了一些实用的方法来处理 URL 的查询字符串,内置了一些常用API,详情参考 URL地址技能