type
status
date
slug
summary
tags
category
icon
password
引言:Axios 的两种常见用法
如果你经常和后端 API 打交道,一定对 Axios 这两种调用方式非常熟悉:
- 配置对象式调用:
axios(config)
- 便捷方法调用:
axios.method(url, [data], [config])
这两种方式都能发起网络请求,非常方便。但你是否想过:
axios 变量到底是什么?为什么它既能像函数一样直接调用 axios({...}),又能像对象一样调用 axios.post(...) 这样的方法?这背后是怎样的设计巧思?
探究 Axios 的设计原理
要理解这一点,我们需要深入了解 Axios 的核心构造过程。
1. 基础:
Axios 构造函数与原型方法从概念上讲,Axios 内部首先有一个核心的
Axios 类(构造函数),它负责管理配置(defaults)和拦截器(interceptors):2. 问题的出现:实例只是对象,不是函数
按照传统的面向对象方式,我们会创建一个
Axios 的实例来使用:但是,我们无法直接像函数一样调用这个实例:
这与我们平时使用的
axios({...}) 方式不符。那么,我们导入的那个 axios 究竟是如何做到既是函数又是对象的呢?3. Axios 的精妙之处:
createInstance 工厂函数Axios 的开发者使用了一个非常巧妙的技巧,通过一个工厂函数
createInstance 来创建我们最终使用的 axios 对象。以下是其核心思想的简化和实际源码的结合:解读
createInstance 的魔法:axios首先是一个函数: 因为instance本身是通过bind创建的函数(Axios.prototype.request.bind(context)),所以你可以直接调用axios(config)。
axios又是一个对象,拥有方法: 通过Object.keys(Axios.prototype).forEach(...)循环,get,post等方法被直接添加为instance函数对象的属性。因此,你可以使用axios.get(...),axios.post(...)等。
axios还拥有属性: 通过Object.keys(context).forEach(...)循环,defaults,interceptors等实例属性也被添加为instance函数对象的属性,所以axios.defaults和axios.interceptors.request.use(...)也能工作。
this指向正确: 整个设计的关键在于bind(context)。无论你是调用axios(config)还是axios.get(...),最终执行的方法内部的this都被正确地指向了包含配置和拦截器的context实例,确保了 Axios 能正确运行。
源码中的
this 绑定为何如此重要?我们看看
Axios.prototype.request 方法内部(简化示意):如果
request 方法在被调用时,其内部的 this 不是指向 Axios 的实例 (context),那么访问 this.defaults 和 this.interceptors 就会出错。这就是为什么 createInstance 中必须使用 bind(context) 来确保 this 指向正确。总结
Axios 之所以能支持
axios(config) 和 axios.get(...) 两种调用方式,归功于其 createInstance 工厂函数的精妙设计。它返回的 axios 对象是一个“混合体”:- 它本质上是一个函数 (是绑定了正确
this的Axios.prototype.request方法)。
- 它又被动态地添加了
get,post等方法属性 (同样绑定了正确的this)。
- 它还被添加了
defaults,interceptors等实例属性。
这种设计模式,利用了 JavaScript 函数即对象的特性,创造出了一个既灵活又强大的 API 接口,堪称 JavaScript 库设计的典范。
- 作者:90_blog
- 链接:https://blog.tri7e.com/article/axios_js
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
