■ 檢視原始碼發現,起初axios【instance=bind(Axios.prototype.request, context);】是一個函式,
但後續【 utils.extend(instance, Axios.prototype, context);】又給它新增上了一些方法屬性。
✿ axios 函式物件可以呼叫自身axios(config)
傳送請求也可以呼叫屬性的方法axios.request(config)
傳送請求的原理:(看學習axios必知必會(2)https://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>