源碼分析axios(1)~源碼分析、模擬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動態添加了屬性方法

requestgetUri

‘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>