欢迎光临
我们一直在努力

Axios 源码解析:axios 与 Axios 的关系

前言

在使用 Axios 时,我们通常会遇到两种调用方式:

// 方式一:直接传入配置对象
axios({
method: 'post',
url: '/user/12345',
data: { firstName: 'Fred' }
});

// 方式二:调用具体的方法
axios.get('/user?ID=12345');
axios.post('/user', { firstName: 'Fred' });

那么,axios 和 Axios 之间到底是什么关系呢 ?源码底层又是如何实现这两种调用方式的?

一、核心关系概述

在 Axios 源码中:

  • Axios:是一个构造函数(类),用于创建 Axios 实例。它的原型(prototype)上定义了 request、get、post、put、delete 等核心请求方法。 在这里插入图片描述

  • axios:是一个通过内部工厂函数创建出来的实例对象,本质上是一个函数(可以被调用),它指向了 Axios.prototype.request 方法,并且通过 bind 将 this 固定绑定了。

  • 简单来说:axios 是 Axios 的一个实例,但它被设计成一个可直接调用的函数,同时还继承了原型上的所有方法。 在这里插入图片描述

二、源码关键行解析

1. 创建 Axios 实例(context)

// 第 21 行左右
var context = new Axios();

  • 创建了一个 Axios 的实例对象,命名为 context。
  • 这个 context 拥有 Axios.prototype 上定义的所有方法:request、get、post、put、delete 等。

2. 绑定 request 方法的 this 指向

// 第 25 行左右
var instance = bind(Axios.prototype.request, context);

  • Axios.prototype.request 是一个综合请求方法,内部会访问 this.defaults(默认配置)和 this.interceptors(请求/响应拦截器),并最终发起请求。
  • bind 函数将 request 方法的 this 永久绑定为 context(即 Axios 实例),确保 request 能正确读取配置和拦截器。
  • 返回的函数赋值给 instance,也就是我们最终使用的 axios。
为什么需要绑定 this?

因为 request 方法内部有这样的逻辑(简化版):

// 伪代码
Axios.prototype.request = function(config) {
// 合并默认配置和用户配置
config = mergeConfig(this.defaults, config);
// 将拦截器和请求串联成链条
var chain = [dispatchRequest, undefined];
this.interceptors.request.forEach();
this.interceptors.response.forEach();
// … 执行链条
};

如果 this 指向全局对象(window/global),那么 this.defaults 和 this.interceptors 都会是 undefined,导致请求失败。因此必须通过 bind 将 this 固定指向 Axios 实例(context)。

3. 将原型方法拷贝到 instance 上

// 第 28 行左右
utils.extend(instance, Axios.prototype, context);

  • utils.extend 方法将 Axios.prototype 上的所有属性和方法(get、post、put、delete 等)拷贝到 instance 对象上。
  • 同时将方法的 this 绑定为 context,确保这些方法执行时的上下文正确。
这一步的作用

经过这一步,instance不仅是一个可以直接调用的函数,还拥有了 axios.get、axios.post 等快捷方法。

// 现在 instance 既可以这样用
instance({ method: 'get', url: '/user' });

// 也可以这样用
instance.get('/user');
instance.post('/user', { name: 'John' });

最后,将instance返回给axios,axios也就具备了这些能力。 在这里插入图片描述

三、两种调用方式的底层原理

方式一:axios(config)

axios({
method: 'get',
url: '/user'
});

  • 这里的 axios 就是经过 bind 处理后的 request 函数。
  • 调用时,实际上执行的是 Axios.prototype.request,且内部的 this 指向 context(Axios 实例)。
  • request 方法会根据 config.method 等参数,最终调用对应的请求方法。

方式二:axios.get(url, config)

axios.get('/user', { params: { id: 123 } });

  • 这里的 axios.get 是从 Axios.prototype 上拷贝到 instance 上的方法。
  • 调用时,它的 this 同样被绑定到了 context,因此可以正常访问实例上的其他属性和方法。
  • 本质上,get 方法内部也是调用了 request 方法,只是帮我们预设了 method: 'get'。

四、设计意图总结

特性说明
Axios 构造函数,核心请求逻辑都在它的原型上实现
axios 通过 bind 和 extend 创建出的“混合对象”,既是一个函数,又是一个拥有快捷方法的对象
为什么要这样做 为了让开发者可以使用两种风格来发起请求,提升灵活性和代码可读性
this 绑定的必要性 确保 request 内部能够正确访问 defaults 和 interceptors 等实例属性

五、流程图解

在这里插入图片描述

六、核心结论

axios 实际上是一个被改造过的函数,它通过 bind 将 request 方法的 this 固定指向了 Axios 实例(context),并通过 extend 将原型上的请求方法拷贝到了自身。这样axios就同时支持了函数调用和链式方法调用两种风格。

  • bind 的作用是绑定 this,确保 request 内部能正常访问 this.defaults 和 this.interceptors;
  • extend 的作用是拷贝方法,让 axios 可以直接使用 .get、.post 等快捷方式;
  • 两者结合,使 Axios 既保持了核心逻辑清晰,又提供了灵活的 API 设计。

七、补充:create 函数

源码中,默认导出的 axios 是通过内部工厂函数 createInstance(defaultConfig) 直接生成的。createInstance(defaultConfig)内部会执行上述 bind + extend 流程,并返回一个功能完整的实例。

而我们平时使用的 axios.create() 是暴露给用户的一个 API,是用赖创建一个新的、独立的 Axios 实例(拥有自己的 defaults 和 interceptors)。它的内部实现也是复用了同一个 createInstance 工厂函数。

因此,无论是默认的 axios 还是通过 axios.create() 创建的新实例,它们都遵循同样的构建机制,都支持两种调用方式。

希望这篇文章能帮助你理解 axios 和 Axios 之间的关系,以及源码中 bind 和 extend 的巧妙设计。如果你对源码感兴趣,建议可以去看看 Axios 的源代码(lib/axios.js 和 lib/core/Axios.js),会有更深的体会。 axios源码链接

赞(0)
未经允许不得转载:171主机测评 » Axios 源码解析:axios 与 Axios 的关系
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址