【若川视野 x 源码共读】第19期 | axios 工具函数

149 阅读5分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

  1. 判断是否为数组
 * 用Array.isArray判断是否是数组
 * 也可使用Object.prototype.toString.call(params),判断对象的类型
 * @param {Object} val
 * @returns {Boolean}  
 */
function isArray(val) {
    return Array.isArray(val)
}

var arr = [1, 2, 3]
console.log(isArray(arr)); //true;
  1. 判断是否为undefined,用typeof和全等判断
/** 
 * @param {Object} val
 * @returns {Boolean} 
 */
function isUndefined(val) {
    return typeof val === 'undefined'
}

console.log(isUndefined(2)); //false
console.log(isUndefined(undefined));//true;
  1. 判断是否为buffer(二进制数据的缓存区),它是一个类
/**
 * 1. 判断参数是否为underfined和null
 * 2. 判断buffer是否存在构造函数
 * 3. 用buffer下面的方法判断参数是否为buffer
 * @param {Object} val 
 * @returns {Boolean}
 */
function isBuffer(val) {
    return val !== null &&
        !isUndefined(val) &&
        val.constructor !== null &&
        !isUndefined(val.constructor) &&
        typeof val.constructor.isBuffer === 'function' &&
        val.constructor.isBuffer(val)
}

var a = Buffer.alloc(10)
console.log('a: ', a);
console.log(isBuffer(a));//true;
  1. 判断是否为对象
/**
 * 
 * 先判断它是否为null,因为typeof判断null也为对象.
 * 不是则判断它是否为对象
 * 
 */
function isObject(val) {
    return val !== null && typeof val === 'object'
}
  1. let toString = Object.prototype.toString;,将toString函数提取出来作为公共函数,这一点和vue2的工具函数很像

  2. 判断是否为函数

 function isFunction(val){
     return toString.call(val) ==='[object Function]'
 }
 
 let d = function t(){}
 console.log('isFunction',isFunction(d));//true;
  1. 判断是否为FormData的实例
/** 
 * 判断是否为FormData的实例
 * instanceof 用于判断构造函数的prototype是否在某个实例的原型链上
 * 1. 判断参数是否存在
 * 2. 判断FormData是否为函数且FormData的prototype是否在参数的原型链上
 * 3. 用Object.prototype.toString判断参数类型
 * 4. 判断参数的toString是否为函数并且调用后是否为'[object FormData]'
 * Object.getPrototypeOf(params)获取对象的原型
 * isPrototypeOf(params),判断一个对象是否在另一个对象的原型链上
 * toString返回一个对象的字符串形式
 * @param {*} thing 
 * @returns {Boolean}
 */
function isFormatData(thing){
    var pattern = '[object FormData]';
    return thing&&(typeof FormData === 'function'&&thing instanceof FormData||
    toString.call(thing)===pattern ||
    (isFunction(thing.toString)&& thing.toString()===pattern))
}
  1. 类型判断帮助函数,它是一个自执行函数,默认的参数为一个没有原型的空object
/**
 * 类型判断帮助函数,它是一个自执行函数,默认的参数为一个没有原型对象
 * 利用toString获取对象的字符串形式
 * 当参数对象里有以这个字符串为key的value,返回这个value
 * 否则则设置以这个字符串为key的value,然后返回
 * */
var kindOf = (function(cache){
    return function(thing){
        var str = toString.call(thing);
        return cache[str] || (cache[str] = str.slice(8,-1).toLowerCase())
    }
  
})(Object.create(null))

let j = {a:1}
console.log('kindOf(j)',kindOf(j)); //object;

  1. 判断是否是{}或new Object出来的对象,非日期,正则对象
/**
 * 用类型帮助函数判断参数的类型
 * 然后判断参数的原型是否为null或者为Object.prototype
 * @param {*} val 
 * @returns {Boolean}
 */
function isPlainObjct(val){
    if(kindOf(val)!=='object'){
        return false;
    }
    var prototype = Object.getPrototypeOf(val);
    return prototype ===null || prototype===Object.prototype
}

function C(){};
let c = new C();

console.log(isPlainObjct(c));
  1. 类型匹配帮助函数(kindof)的进一步封装,传入的参数即为默认需判断的对象类型,返回一个判断与该对象类型是否匹配的函数
/**
 * @param {*} type 预设的对象类型
 * @return {Boolean} 
 */

function kindOfTest(type){
    type = type.toLowerCase();
    return function isKindOf(thing){
        return kindOf(thing) === type
    }
}
  1. isDate是kindOfTest返回的函数,用来判断是否为日期类型
var isDate = kindOfTest('Date')
var k = isDate('1122')
console.log('k: ', k); //false;
  1. isFile是kindOfTest返回的函数,用来判断是否为文件类型
var isFile = kindOfTest('File')
  1. isBlob是kindOfTest返回的函数,用来判断是否为Blob类型
var isBlob = kindOfTest('Blob')
  1. isURLSearchParams是kindOfTest返回的函数,用来判断是否为URLSearchParams类型,它用来处理url查询字符串的
var isURLSearchParams= kindOfTest('URLSearchParams')
  1. 判断是否为二进制流
/**
 * 
 * 1. 先判断val是否为对象
 * 2. 再判断val.pipe是否为函数
 * @param {*} val
 * @returns {Boolean}
 */
function isStream(val){
    return isObject(val) && isFunction(val.pipe)
}
  1. 去除字符串左右两边的空格
/**
 * 
 * 1. 存在trim方法,则使用trim方法
 * 2. 否则用正则配合replace方法去除空格
 * @param {string} str
 * @returns {string}
 */
function trim(str){
    return str.trim? str.trim():str.replace(/^\s+|\s+$/g,'')
}
let str = '  1234   '
console.log(trim(str).length); //4;

  1. 判断是否是在标准的浏览器环境
/**
 * 让axios能在web worker和react-native环境里使用
 */
function isStandardBrowserEnv(){
    if(typeof navigator!=="undefined"
    &&(navigator.product==='ReactNative'||
    navigator.product==="NativeScript"||
    navigator.product ==="NS")){
        return false;
    }
    return (
        typeof window !=='undefined'&&
        typeof document !=='undefined'
    )
}
console.log('isStandardBrowserEnv',isStandardBrowserEnv());//在浏览器环境下返回true
  1. 实现一个对数组和对象都能迭代的forEach
function forEach(obj,fn){
    // 如果obj为假值,则直接返回
    if(obj==null || typeof obj ==='undefined'){
        return
    }
    //如果obj不是对象,则将其转化成数组
    if(typeof obj!=='object'){
        obj =[obj]
    }
    // 如果是数组,用for循环迭代
    if(isArray(obj)){
        for (var i = 0; i < obj.length; i++) {
            fn.call(null,obj[i],i,obj)
            
        }
    }else{
        // 如果是对象的话,用for in迭代,并且只迭代自身有的值
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj,key)) {
                fn.call(null,obj[i],key,obj)
                
            }
        }
    }
}

forEach([1,2,3],function(item,i,arr){
    console.log('item: ', item,i,arr);
})
  1. 移除BOM
/**
 * 移除字节顺序标记(BOM),BOM出现在文件头部,在Unicode中指定文件的编码
 * UTF-8中是不需要这个BOM的,它是单字节的,顺序对UTF-8是不那么重要的    
 */

 function stripBOM(content){
     if(content.chrCodeAt(0)===0xFEFF){
         content = content.slice(1)
     }
     return content;
 }
  1. 关于BOM的参考资料 1. docs.microsoft.com/en-us/globa… 2. [blog.csdn.net/weixin_3964…

  2. 总结:

    1. axios的注释,第一行一般说明函数的作用,可能会附带一些对这个函数的说明,第二行一般是说明传入参数的类型及参数本身,第三行一般是说明返回的类型。感觉这样看到这个函数你就能清晰的知道这个函数的作用、参数及返回值。平常写代码也可以借鉴。
    2. vue2和axios的工具函数看代码,都喜欢用Object.prototype.toString来判断对象的类型。不同的是它俩根据自身的目的进行不同的封装
    3. axios的工具函数就像乐高积木一样,一块小的功能结合其他功能就能构造出一个更大的功能。比如kindOfTest就是用kindOf构建起来的。这种思路可以借鉴。