axios为什么可以使用对象和函数两种方式调用?是如何实现的?
Axios 可以使用对象和函数两种方式调用,是因为它的核心 API 设计利用了函数重载和 JavaScript 的灵活性。 本质上,Axios 暴露的顶层 axios
对象既是一个函数,又是一个拥有属性的对象。
以下是它的实现方式:
-
Axios 对象是一个函数: 当你像这样调用
axios(config)
时,你实际上是在直接调用 Axios 对象本身。这个函数内部会处理配置config
,并发起请求。 -
Axios 对象拥有方法 (HTTP verbs):
axios.get(url[, config])
、axios.post(url[, data[, config]])
等方法是 Axios 对象的属性。这些方法是对axios()
函数的封装,它们预设了 HTTP 方法,并简化了常见请求的调用方式。 例如,axios.get(url, config)
内部会调用axios({...config, method: 'get', url})
。 -
函数重载 (通过参数类型判断):
axios()
函数内部会根据传入参数的类型进行不同的处理。如果传入的是一个配置对象config
,它会直接使用这个配置发起请求。如果传入的是 URL 字符串,它会将 URL 视为config.url
,并创建一个默认的 GET 请求配置。
// Simplified example of how axios might be implemented internally
function axios(configOrUrl, data, config) {
let finalConfig = {};
if (typeof configOrUrl === 'string') { // URL as first argument
finalConfig.url = configOrUrl;
finalConfig.method = 'get'; // Default to GET
if (data) { // Second argument is data if provided
finalConfig.data = data;
}
if (config) { // Third argument is config
finalConfig = { ...finalConfig, ...config };
}
} else if (typeof configOrUrl === 'object') { // Config object as first argument
finalConfig = { ...configOrUrl };
if (data) {
finalConfig.data = data; // Overwrite data if provided as second argument (less common)
}
} else {
throw new Error('Invalid arguments provided to axios');
}
// ... rest of the axios logic to make the request using finalConfig
return makeRequest(finalConfig);
}
// Adding HTTP verb methods to the axios object
axios.get = function(url, config) {
return axios({ ...config, method: 'get', url });
};
axios.post = function(url, data, config) {
return axios({ ...config, method: 'post', url, data });
};
// ... other HTTP verb methods (put, delete, patch, etc.)
// Example usage:
// Object style
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// Function style (GET)
axios('/user/12345').then(response => { /* ... */ });
// Function style (POST) - less common, can be confusing
axios('/user/12345', { firstName: 'Fred' }).then(response => { /* ... */ });
// Using convenience methods
axios.get('/user/12345').then(response => { /* ... */ });
axios.post('/user/12345', { firstName: 'Fred' }).then(response => { /* ... */ });
通过这种巧妙的设计,Axios 提供了灵活的 API,开发者可以根据自己的喜好和需求选择不同的调用方式。 使用对象方式可以进行更精细的配置,而使用函数方式则更加简洁方便。