type
status
date
slug
summary
tags
category
icon
password
引言:Axios 的双重调用方式
对于经常与后端 API 打交道的开发者来说,Axios 无疑是一个得力助手。我们通常会使用以下两种方式来发起请求:
- 配置对象式调用:
axios(config)
- 便捷方法式调用:
axios.verb(url, [data], [config])
这两种方式都非常方便,但你是否曾好奇:
axios 变量本身到底是什么?为什么它既可以像函数一样被直接调用 axios({...}),又可以像对象一样拥有 .get(), .post() 等方法?这背后是怎样巧妙的设计?
传统思路的困境:标准类与实例
如果我们尝试用传统的面向对象思路来构建一个类似 Axios 的库,可能会这样做:
- 定义一个
Axios类: 包含配置 (defaults) 和拦截器 (interceptors)。
- 在原型上添加请求方法:
- 创建实例:
现在,我们可以使用
myAxiosInstance.get('/users') 或 myAxiosInstance.post('/users', {...})。这看起来很符合直觉。但是,问题来了:
myAxiosInstance 是一个对象实例,我们无法像函数一样直接调用它,即 myAxiosInstance({...}) 是非法的。这与 Axios 的实际用法不符。那么,Axios 是如何突破这个限制的呢?
Axios 的核心设计:函数也是对象!
Axios 的精妙之处在于它利用了 JavaScript 中函数本身也是对象的特性。我们最终从
axios 库导入的那个 axios 变量,它本质上是一个函数,但同时又被赋予了额外的属性和方法。让我们看看这个核心思想的简化实现:
剖析关键点:
instance首先是一个函数:Axios.prototype.request.bind(context)的返回值是一个新的函数。这个新函数在被调用时,其内部的this会被强制指向context(即Axios的实例)。这就是为什么axios(config)能工作的原因——它实际上是在调用绑定了正确上下文的request方法。
- 函数也是对象,可以挂载属性: JavaScript 的函数是“一等公民”,它们可以像普通对象一样拥有属性。代码通过
instance[key] = ...的方式,将get,post等方法以及defaults,interceptors属性“挂载”到了instance这个函数对象上。这就是为什么axios.get(),axios.post(),axios.defaults等能够工作。
bind(context)的重要性:Axios原型上的方法(如request,get,post)在内部实现时,通常需要访问this.defaults或this.interceptors。如果不使用.bind(context),当这些方法被赋值给instance并通过instance.get()调用时,方法内部的this将指向instance函数本身或全局对象(取决于调用方式和严格模式),而不是我们期望的Axios实例context,从而导致错误。bind确保了无论这些方法如何被调用,它们的this始终指向包含配置和拦截器的context对象。
结论:精妙的混合体
Axios 通过
createInstance 工厂函数,巧妙地创建了一个“混合体”:- 它本质上是一个函数(绑定了
this的request方法),可以直接调用。
- 它同时又是一个对象,被动态地添加了其他便捷方法(
get,post等)和实例属性(defaults,interceptors)。
这种设计充分利用了 JavaScript 函数的特性,提供了一个既灵活又易用的 API,让开发者可以通过两种直观的方式进行调用,堪称 JavaScript 设计模式的典范。下次使用 Axios 时,不妨回味一下这个精妙的设计!
- 作者:90_blog
- 链接:https://blog.tri7e.com/article/axios_shouxie
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

