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