# axios 对象创建过程
我们平常在使用的时候,会直接通过import axios from 'axios'引入axios对象,然后使用。那么这个axios对象到底是怎么来的呢?
本章节将会讲述 axios 对象创建的详细过程
# 源码分析
我们先来分析一下源码,源码是在lib/axios.js文件
var utils = require("./utils");
var bind = require("./helpers/bind");
var Axios = require("./core/Axios");
var mergeConfig = require("./core/mergeConfig");
var defaults = require("./defaults");
// 创建一个axios实例
function createInstance(defaultConfig) {
// 通过`new`得到一个`Axios`实例,但是最终return的并不是这个实例
var context = new Axios(defaultConfig);
// 获取`Axios`原型链上面的`request`方法,并将其this绑定为context
// 这里实际上可以写成`Axios.prototype.request.bind(context)`
var instance = bind(Axios.prototype.request, context);
// 遍历`Axios.prototype`原型上面的属性和方法,然后挂载到`instance`上面。如果是方法就需要将`this`绑定为`context`
utils.extend(instance, Axios.prototype, context);
// 循坏`context`实例上面的属性,并挂载到`instance`上面
// 实际`context`实例上面就只有`defaults`和`interceptors`2个属性
utils.extend(instance, context);
return instance;
}
// 创建一个默认的axios对象,并将其导出
var axios = createInstance(defaults);
// 挂载`Axios`类
axios.Axios = Axios;
// 挂载`create`方法,用来创建新的axios对象
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// 挂载取消请求的相关东西
axios.Cancel = require("./cancel/Cancel");
axios.CancelToken = require("./cancel/CancelToken");
axios.isCancel = require("./cancel/isCancel");
// 添加all和spread方法
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = require("./helpers/spread");
// 导出axios
module.exports = axios;
module.exports.default = axios;
# 创建流程
我们把注意力集中在createInstance这个函数当中,axios对象的创建流程如下:
1、 通过new Axios得到一个context上下文实例
2、 获取Axios.prototype.request函数,并将函数的this绑定为context,得到一个instance函数
3、将Axios.prototype对象上面的属性和方法逐一挂载到instance函数上面,如果挂载的是一个函数,还需要把该函数的this绑定为context
4、将context实例上面的属性逐一挂载instance函数上面
5、调用createInstance函数创建一个默认的axios对象,并导出
# 其他
现在我们把注意力集中在 var axios = createInstance(defaults); 这行代码后面的代码当中。
我们可以发现,Axios,Cancel,CancelToken,isCancel,create,all,spread这些类,函数,属性只有在默认导出的axios对象上面才存在的,通过axios.create创建的对象上面是不存在的。所以我们在使用这些函数或者属性的时候,要特别注意我们当前使用的是默认导出的对象还是使用axios.create创建的对象
# 注意点
细心的小伙伴可能会发现源码当中有这么 2 行代码:
utils.extend(instance, Axios.prototype, context);
utils.extend(instance, context);
其中 utils.extend(A,B) 函数是把B的属性或者方法挂在到A中
有人可能会有疑问,context实例上已经存在了Axios.prototype上面的属性和方法,比方说Axios.prototype上面存在一个request方法,那么我们可以通过context.request去访问这个方法。为什么需要utils.extend(instance, Axios.prototype, context)这一行代码呢。
其实,在 js 中遍历一个对象的时候,是不能遍历到该对象所指向的prototype原型链上面的属性和方法,只能遍历到对象上本身的属性和方法。下面举个例子:
function People() {
this.defaults = {};
this.say = () => {};
}
People.prototype.sleep = function() {};
const demo = new People();
for (const key in axios) {
console.log(key);
}
// defaults,say
上面代码示例中输出的结果是defaults,say,虽然sleep方法可以通过demo.sleep去访问,但是却不能通过遍历去访问。所以才会需要以上 2 行代码,分别遍历挂载Axios.prototype和context上面的属性和方法到instance函数上。
还有人可能会发现,utils.extend(instance, Axios.prototype, context)是传入了三个参数,utils.extend(instance, context)指传了两个参数。
Axios.prototype上面存在了一些函数,我们在挂载这些函数到instance函数上面的时候,需要修改this的指向为context,所以传了第三个参数。但是context实例遍历的时候,只存在属性,不会存在函数(跟Axios构造函数的组成有关),属性是不需要修改this的指向,所以不需要传入第三个参数(就算传了也没关系)。关于Axios构造函数是如何组成的,我们将会在下一个章节中讲解到,了解到Axios构造函数的内部组成之后,你就会更加清晰为什么context实例再遍历的时候,只会存在属性了。
# 简单代码实现
经过上述的学习,我们应该了解到了axios对象的创建过程了,下面,我们根据自己的理解去现实一个简单的代码,来加深印象。
function Axios(defaultConfig) {
this.defaultConfig = defaultConfig;
}
Axios.prototype.request = function(config = {}) {};
Axios.prototype.get = function(config = {}) {};
function createInstance(config) {
const context = new Axios(config);
// 创建请求函数
const instance = Axios.prototype.request.bind(context);
// 将Axios.prototype中的request,post等方法挂载到instance请求函数中
Object.keys(Axios.prototype).forEach((key) => {
instance[key] = Axios.prototype[key].bind(context);
});
// 将context中的defaultConfig挂载到instance请求函数中
Object.keys(context).forEach((key) => {
instance[key] = context[key];
});
return instance;
}
const axios = createInstance(defaults);
# 总结
axios对象实际上是通过Axios.prototype.request函数通过bind(context)创建出来的(并不是通过new Axios创建出来的),只是this的指向发生了变化。Axios构造函数上面存在的属性和方法,axios对象都有。axios对象实际上就是Axios.prototype.request函数,只是添加一系列属性和方法在这个函数上面
在本章中,我们看见Axios构造函数,在下一个章节中,我们将会分析Axios构造函数的内部组成
← 准备工作 Axios 构造函数分析 →