源碼分析axios(1)~源碼分析、模擬axios的創建
- 2022 年 1 月 24 日
- 筆記
- 源碼分析、模擬axios的創建
■ 查看源碼發現,起初axios【instance=bind(Axios.prototype.request, context);】是一個函數,
但後續【 utils.extend(instance, Axios.prototype, context);】又給它添加上了一些方法屬性。
✿ axios 函數對象可以調用自身axios(config)
發送請求也可以調用屬性的方法axios.request(config)
發送請求的原理:(看學習axios必知必會(2)//www.cnblogs.com/shan333/p/15836026.html)
一、源碼分析axios的創建
1、查看axios的實例對象new Axios(defaultConfig);
① 在類Axios 發現有配置對象和攔截器對象屬性
② 在Axios.js 文件中,還發現Axios的原型:Axios.prototype動態添加了屬性方法
request,getUri,
‘delete’, ‘get’, ‘head’, ‘options’,
‘post’, ‘put’, ‘patch’
■ axios的創建的源碼:
// 通過配置創建 axios 函數
var axios = createInstance(defaults);
function createInstance(defaultConfig) {
//創建一個實例對象 context 可以調用 get post put delete request
var context = new Axios(defaultConfig);// context 不能當函數使用
……
}
//在 Axios 類內有屬性 配置對象和攔截器對象
function Axios(instanceConfig) {
//實例對象上的 defaults 屬性為配置對象
this.defaults = instanceConfig;
//實例對象上有 interceptors 屬性用來設置請求和響應攔截器
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
// 在Axios.js 文件中,還發現:
Axios.prototype.request = function request(config) {
……
}
Axios.prototype.getUri = function getUri(config) {
……
}
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function (url, config) {
……
}
}
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function (url, data, config) {
……
}
}
2、接著是instance:
首先是通過方法bind將request方法賦值給instance(此時instance是一個函數變數);
然後,通過方法extends 將Axios.prototype 上的方法添加到 instance身上(此時instance是一個
「函數對象」變數);還將實例對象content的屬性(配置對象和攔截器對象屬性)添加到instance身上
■ axios的創建的源碼:
function createInstance(defaultConfig) {
//創建Axios的實例對象 context
var context = new Axios(defaultConfig);//context 是實例對象,不能當函數使用
//將request 方法的 this 指向 context 並返回新函數 (instance 與 Axios.prototype.request 程式碼一致)
var instance = bind(Axios.prototype.request, context); //instance是函數,可以用作函數使用
//將Axios的原型 Axios.prototype 的方法都添加到 instance 函數身上
utils.extend(instance, Axios.prototype, context); //instance是"函數對象",可當函數使用,也可當對象使用
//將實例對象content的方法和屬性添加到 instance 函數身上
utils.extend(instance, context);
return instance;
}
■ bind函數:
//返回一個新的函數,並將新函數 this 綁定到一個對象身上
module.exports = function bind(fn, thisArg) {
return function wrap() {
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return fn.apply(thisArg, args);
};
};
■ extend函數:
function extend(a, b, thisArg) {
forEach(b, function assignValue(val, key) {
if (thisArg && typeof val === 'function') {
a[key] = bind(val, thisArg);
} else {
a[key] = val;
}
});
return a;
}
二、模擬axios的創建
❀ 實現調用axios(config)自身發送請求、調用axios對象的方法屬性 axios.request(config)發送請求
<script>
//構造函數
function Axios(config) {
//初始化
this.defaults = config;//default默認屬性
this.intercepters = {
request: {},
response: {}
}
}
//為類的原型添加相關方法
Axios.prototype.request = function (config) {
console.log('發送ajax請求,請求類型:' + config.method)
}
Axios.prototype.get = function (config) {
return this.request({method: 'GET'})
}
Axios.prototype.post = function (config) {
return this.request({method: 'POST'})
}
//聲明函數
function createInstance(config) {
//實例化一個對象
var context = new Axios(config); //實例對象可以調用方法,例如 context.get() 但是不能直接當函數使用 context() ×
var instance = Axios.prototype.request.bind(context);//instance 是一個函數,並且可以 instance({}),
//但是因為bind返回的是一個函數(一個擁有了Axios.prototype.request() 方法的函數,而instance的參數就是Axios的實例),所以不能 instance.get()
//將Axios.prototype 對象中的方法添加到instance函數中,讓instance擁有get、post、request等方法屬性
Object.keys(Axios.prototype).forEach(key => {
// console.log(key); //修改this指向context
instance[key] = Axios.prototype[key].bind(context);
})
//總結一下,到此instance自身即相當於Axios原型的request方法,
//然後又給instance的屬性添加了上了Axios原型的request、get、post方法屬性
//然後調用instance自身或instance的方法屬性時,修改了this指向context這個Axios實例對象
//為instance函數對象添加屬性 default 與 intercetors
Object.keys(context).forEach(key => {
instance[key] = context[key];
})
// console.dir(instance);
return instance;
}
//測試一下axios的創建過程
let axios = createInstance();
//發送Ajax請求
axios({method: 'POST'});
axios.post({});
</script>