axios 源码分析 - 学习utils中的方法(原型相关)

135 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情


前言

axios是前端主流的http库,基于promise,可以用在浏览器node.js中使用,为了提高效率,axios使用了一些工具库(utils),这是一个非axios特有的通用帮助函数库,本文对这个文件的重点函数(原型相关)进行解析,可以让我们更好的理解axios源码和学习。

utils.js

var bind = require('./helpers/bind');

开头引入了bind函数,我们看下源码

module.exports = function bind(fn, thisArg) {
  return function wrap() {
    return fn.apply(thisArg, arguments);
  };
};

bind函数接收2个参数,第一个是传入的fn(function),第二个是要给他绑定的this(thisArg)bind函数返回一个wrap方法,wrap中使用了fn.apply方法,会把调用bind()函数的参数传给fn使用,并且使用thisArg作为给定的this


var toString = Object.prototype.toString;

由于大多数toString方法被改写,所以我们通过Object.prototype去拿原始toString方法。


var kindOf = (function(cache) {
  return function(thing) {
    var str = toString.call(thing);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  };
})(Object.create(null));
  • 这里的kindOf是个IIFE方法,通过Object.create(null)新创建了个对象,当作实参传给了匿名函数使用,返回了个方法,如果该参数(thing)不存在,则截取该方法的类型,并返回,如果该参数(thing)已经存在了缓存当中,则直接返回
  • 这个方法的核心其实就是通过Object.prototype.toString.call() + slice,对参数进行截取,并缓存在我们新创建的对象中(Object.create(null))

image.png


function kindOfTest(type) {
  type = type.toLowerCase();
  return function isKindOf(thing) {
    return kindOf(thing) === type;
  };

kindOfTest方法是一个简单的高阶函数,传一个类型比如string,然后定义好再传一个参数判断是否相等这个类型,内部是通过上面的kindOf()方法进行判断。


function isBuffer(val) {
  return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
    && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}
  • Buffer:Node.js提供的一个二进制缓冲区,常用来处理I/O操作,js没有判断缓冲区的方法,所以用这个函数来判断是不是Buffer
  • 这里用到的isUndefined源码:isUndefined = (val) => typeof val === 'undefined';
  • val的原型上如果有isBuffer方法,会返回boolean,所以也需要判断一下

function isPlainObject(val) {
  if (kindOf(val) !== 'object') {
    return false;
  }

  var prototype = Object.getPrototypeOf(val);
  return prototype === null || prototype === Object.prototype;
}
  • 判断是否为普通对象的方法
  • 先看第一步,上面写了kindOf函数,它的原理是使用了Object.prototype.toString.call()来判断类型([Symbol.toStringTag]),所以也可以判断出null和普通对象的区别
  • Object.getPrototypeOf()会返回指定对象的原型
  • Object.create(null)[Symbol.toStringTag]object,但他的原型对象又是null,这种也属于普通对象
  • 普通的(几乎所有)JavaScript对象都是Object的实例,其原型链上最后一个就是指向Object.prototype,只要查找到,肯定就是普通对象

image.png


function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}
  • 这里是用来判断Stream的方法
  • isObject = (val) => val !== null && typeof val === 'object';
  • isFunction = (val) => toString.call(val) === '[object Function]';
  • streampipe方法,所以这里也拿来判断

function trim(str) {
  return str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
  • 替代String.prototype.trim.call方法,如果字符串的这个方法被重写或者找不到,可以通过这一段正则来去除

结语

本文介绍了axios的工具库中部分使用到了原型相关的方法,复习了几个不常用的方法:Object.prototypeof.toString.callObject.getPrototypeOf,并且涉及到了一些原型链相关的知识,还学习了kindOf这个可以缓存变量类型的函数。