# 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 构造函数分析 →