axios 工具函数源码学习

89 阅读3分钟

前言

Axios

工具函数

isArray 是否是数组

var toString = Object.prototype.toString;

// 通过 `toString()` 来获取类型
function isArray(val) {
  return toString.call(val) === '[object Array]';
}

isUndefined 是否是Undefined

function isUndefined(val) {
  return typeof val === 'undefined';
}

isBuffer 是否是buffer

// 边界判断 null 和 undefined
// 判断 `val`存在构造函数
// 最后通过`Buffer`类的`isBuffer`方法判断

function isBuffer(val) {
  return val !== null 
          && !isUndefined(val) 
          && val.constructor !== null 
          && !isUndefined(val.constructor)
          && typeof val.constructor.isBuffer === 'function' 
          && val.constructor.isBuffer(val);
}

isFormData 是否是FormData

// `instanceof` 运算符用于检测构造函数的 `prototype` 属性是否出现在某个实例对象的原型链上 --> mdn

function isFormData(val) {
  return (typeof FormData !== 'undefined') && (val instanceof FormData);
}

isObject 是否是非 null 对象

// 排除 `null`的情况
function isObject(val) {
  return val !== null && typeof val === 'object';
}

isPlainObject 是否是纯对象

function isPlainObject(val) {
  if (Object.prototype.toString.call(val) !== '[object Object]') {
    return false;
  }

  var prototype = Object.getPrototypeOf(val);
  return prototype === null || prototype === Object.prototype;
}

就是未继承任何属性的对象,可用{}new Object()Object.create(null)创建。

isDate 是否是Date

function isDate(val) {
  return Object.prototype.toString.call(val) === '[object Date]';
}

isFile 是否是文件类型

function isFile(val) {
  return Object.prototype.toString.call(val) === '[object File]';
}

isBlob 是否是Blob

function isBlob(val) {
  return Object.prototype.toString.call(val) === '[object Blob]';
}

isFunction 是否是函数

function isFunction(val) {
  return Object.prototype.toString.call(val) === '[object Function]';
}

isStream 是否是流

function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

isURLSearchParams 是否是 URLSearchParams

function isURLSearchParams(val) {
  return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams;
}

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

trim 去除首尾空格

// trim 或者正则
function trim(str) {
  return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
}

isStandardBrowserEnv 是否是标准浏览器环境

function isStandardBrowserEnv() {
  if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
    navigator.product === 'NativeScript' ||
    navigator.product === 'NS')) {
    return false;
  }
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined'
  );
}

forEach 遍历对象或数组

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @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
  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);
      }
    }
  }
}

stripBOM 删除UTF-8编码中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;
}

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

inherits 原型继承

/**
 * Inherit the prototype methods from one constructor into another
 * @param {function} constructor
 * @param {function} superConstructor
 * @param {object} [props]
 * @param {object} [descriptors]
 */

function inherits(constructor, superConstructor, props, descriptors) {
  constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  constructor.prototype.constructor = constructor;
  props && Object.assign(constructor.prototype, props);
}

这里不难理解,只要把prototype操作好了就可以

toFlatObject 对象碾平

/**
 * Resolve object with deep prototype chain to a flat object
 * @param {Object} sourceObj source object
 * @param {Object} [destObj]
 * @param {Function} [filter]
 * @returns {Object}
 */

function toFlatObject(sourceObj, destObj, filter) {
  var props;
  var i;
  var prop;
  var merged = {};

  destObj = destObj || {};

  do {
    props = Object.getOwnPropertyNames(sourceObj);
    i = props.length;
    while (i-- > 0) {
      prop = props[i];
      if (!merged[prop]) {
        destObj[prop] = sourceObj[prop];
        merged[prop] = true;
      }
    }
    sourceObj = Object.getPrototypeOf(sourceObj);
  } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);

  return destObj;
}

将深度对象变成平面对象

toArray 将类数组转数组

/**
 * Returns new array from array like object
 * @param {*} [thing]
 * @returns {Array}
 */
function toArray(thing) {
  if (!thing) return null;
  var i = thing.length;
  if (isUndefined(i)) return null;
  var arr = new Array(i);
  while (i-- > 0) {
    arr[i] = thing[i];
  }
  return arr;
}

类数组:比如集合,比如我们获取标签集合document.querySelectorAll('li')得到的是标签集合,它不具备数组所有特性,比如.map方法

isTypedArray 是否是Uint8Array

// eslint-disable-next-line func-names
var isTypedArray = (function(TypedArray) {
  // eslint-disable-next-line func-names
  return function(thing) {
    return TypedArray && thing instanceof TypedArray;
  };
})(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));

Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。