axios utils工具方法笔记

934 阅读4分钟

前言

参加若川大佬的源码共读活动,这是我一月的参与的第一份源码阅读笔记,也算是新年学习计划的开始。如果有朋友也想参与源码共读活动可以访问若川大佬的掘金首页,了解若川大佬的源码共读活动,括弧,良心大佬的免费活动。

isBuffer

首先判断判断是否为null,然后判断是否为undefined,然后判断constructor是否为null,然后判断constructor上是否存在isBuffer方法, 如果存在的话,使用构造函数上的isBuffer方法判断参数是否为Buffer

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

Buffer为NodeJs 补全二进制操作添加的类,因为本身axios可以跑在node环境与js环境,故有此工具方法。

isArrayBuffer,isFormData,isDate,isFile,isBlob,isFunction

常用的判断方式,通过toString方法来判断是什么类型的数据,平时不经常用ArrayBuffer等,所以没有注意过这些细节,故放到一起增加印象。

var toString = Object.prototype.toString;

function isArrayBuffer(val) {
  return toString.call(val) === '[object ArrayBuffer]';
}

function isFormData(val) {
  return toString.call(val) === '[object FormData]';
}

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

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

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

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

isArrayBufferView

兼容没有ArrayBuffer类的环境,判断传入值是否为ArrayBuffer视图

//ArrayBuffer.isView() 方法用来判断传入的参数值是否是一种 ArrayBuffer 视图(view),
//比如类型化数组对象(typed array objects)或者数据视图( DataView)。
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
  }
  return result;
}

isStream

此方法通过判断是否为对象,且入参下的.pipe方法是否存在判断入参是否为Stream,流。

流是用于在 Node.js 中处理流数据的抽象接口。 stream 模块提供了用于实现流接口的 API。

Node.js 提供了许多流对象。 例如,对 HTTP 服务器的请求process.stdout 都是流的实例。

流可以是可读的、可写的、或两者兼而有之。 所有的流都是 EventEmitter 的实例。

更多关于流的信息,可以参照Node中流一章节

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

isPlainObject

此方法判断对象是否为纯对象,即使用{}new Object() 创建的object,通过是否存在prototype 或者prototype是否等于Object.prototype来判断是否为纯函数。

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

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

isURLSearchParams

此方法判断参数是否为URLSearchParams

function isURLSearchParams(val) {
  return toString.call(val) === '[object URLSearchParams]';
}

URLSearchParams接口定义了一些实用的方法来处理 URL 的查询字符串,关于URLSearchParams的详细定义及方法可以查看这里。这里只稍微提一下具体使用方式,加深一下印象。

//使用字符串新建URL对象
var url = new URL('https://example.com?foo=1&bar=2');
//使用window.location创建URL对象 Retrieve from window.location
var url = new URL(window.location);
console.log(url.search);

//创建URLSearchParams对象,URLSearchParams实现了Symbol.iterator,
//`且entries(), keys(),values()都是iterator
var params = new URLSearchParams(url.search);
//输出键值对
for (const key of params.keys()) {
    console.log(key);	//foo,bar
}

forEach

forEach方法,用来遍历object 和 array,执行特定方法

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);
      }
    }
  }
}

isStandardBrowserEnv

此方法用来判断是否为标准浏览器环境,navigator.product 目前已在mdn提示废弃,我猜测各个非标准浏览器环境仍会支持这个值用以区分浏览器环境,当然后须得关注axios的代码更新。

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

merge

在不修改原参数的情况下合并传入的参数,如果传入参数有重复key,后一个参数的重复key对应的值会覆盖前一个。

function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (isPlainObject(result[key]) && isPlainObject(val)) {
      result[key] = merge(result[key], val);
    } else if (isPlainObject(val)) {
      result[key] = merge({}, val);
    } else if (isArray(val)) {
      result[key] = val.slice();
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

extend

将b的属性添加到a上,并可将b的参数绑定到指定的对象上。

function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

总结

这算是我第一篇正经源码学习笔记,axios的utils工具类写的蛮好的,有ES6的特性,也有一些兼容性的写法,也有一些Node环境下的方法。通过这次的学习,总结了几个问题:对于Node还是有些陌生,很多基础知识不全,之前处于用到什么去学什么的心态,需要改正;优秀的代码看的还是太少,总是显得没见过世面。

最后,axios一直在阅读的日程上,但并没有去执行,趁热打铁,下一发就是axios吧。