■ 查看源码发现,起初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 发现有配置对象和拦截器对象属性
② 在Axios.js 文件中,还发现Axios的原型:Axios.prototype动态添加了属性方法
request,getUri,
'delete', 'get', 'head', 'options',
'post', 'put', 'patch'
// 通过配置创建 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) { …… } }
首先是通过方法bind将request方法赋值给instance(此时instance是一个函数变量);
然后,通过方法extends 将Axios.prototype 上的方法添加到 instance身上(此时instance是一个
“函数对象”变量);还将实例对象content的属性(配置对象和拦截器对象属性)添加到instance身上
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; }
//返回一个新的函数,并将新函数 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); }; };
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; }
<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>