前言
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
源码
在写axsios工具函数之前,大概的过了一下其源码,源码中大量的使用了箭头函数和闭包,以及函数字面量声明,对于一些初级的开发者来说,阅读起来有点儿磕绊,基础薄弱的可以试着将箭头函数还原,对比一下源码和还原的代码,学习大佬的编程方法和思维,对自己很有帮助。
kindOf 判断数据类型
const {toString} = Object.prototype;
const kindOf = (cache => thing => {
const str = toString.call(thing);
return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
})(Object.create(null));
在此呢,我还原一下这个函数,如下
const {toString} = Object.prototype;
function kindCatch (cache) {
return function (thing) {
const str = toString.call(cache);
return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
}
}
const kindOf = kindCatch(Object.create(null));
简单说一下这个函数吧
- 先声明一个函数
kindCatch,接收一个catche参数,作为数据缓存容器 - 这个函数返回的是一个函数,接收一个任意变量
thing,其结果返回的是变量的数据类型 - 最后,得到
kindOf函数,并传入初始实参Object。create(null),就是内部返回的函数
函数执行逻辑
- 传入变量
thing,通过toString.call获得当前变量的类型[object xxxx] - 然后从缓存
catch里读取其类型,有直接返回,没有则将当类型存入catch中 - 最后返回数据的类型
xxxx
函数运行结果
// 此时的catch -> {}
kindOf("Axios"); // string
// 此时的catch -> {'[object String]': 'string'}
kindOf(314); // number
// 此时的catch -> {'[object String]': 'string', '[object Number]': 'number'}
kindOf(true); //boolean
// 此时的catch -> {'[object String]': 'string', '[object Number]': 'number', '[object Boolean]': 'boolean'}
kindOfTest 判断传入的数据类型是否为预定义的类型
const kindOfTest = (type) => {
type = type.toLowerCase();
return (thing) => kindOf(thing) === type
}
源码中使用kindOfTest声明了如下几个函数
// 日期类型
const isDate = kindOfTest('Date');
// 文件类型
const isFile = kindOfTest('File');
// Blob类型
const isBlob = kindOfTest('Blob');
// 文件列表类型
const isFileList = kindOfTest('FileList');
// URL搜索参数类型
const isURLSearchParams = kindOfTest('URLSearchParams');
// HTML表单元素
const isHTMLForm = kindOfTest('HTMLFormElement');
// 正则表达式
const isRegExp = kindOfTest('RegExp');
typeOfTest 判断传入的数据类型是否为预定义的类型
const typeOfTest = type => thing => typeof thing === type;
只是这个类型校验是通过typeof,需要了解typeof与Object.prototype.toString的异同点。
源码中使用typeofTest声明了如下几个函数
// undefined
const isUndefined = typeOfTest('undefined');
// string
const isString = typeOfTest('string');
// function
const isFunction = typeOfTest('function');
// number
const isNumber = typeOfTest('number');
isObject 判断数据是否是object类型
const isObject = (thing) => thing !== null && typeof thing === 'object';
isBoolean 判断数据是否是Booleanl类型
const isBoolean = thing => thing === true || thing === false;
isPlainObject 判断数据是否是普通对象
const {getPrototypeOf} = Object;
const isPlainObject = (val) => {
if (kindOf(val) !== 'object') {
return false;
}
const prototype = getPrototypeOf(val);
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);
}
isFormData 判断数据是否是表单数据
const isFormData = (thing) => {
const pattern = '[object FormData]';
return thing && (
(typeof FormData === 'function' && thing instanceof FormData) ||
toString.call(thing) === pattern ||
(isFunction(thing.toString) && thing.toString() === pattern)
);
}
forEach 回调遍历对象的所有属性值
function forEach(obj, fn, {allOwnKeys = false} = {}) {
if (obj === null || typeof obj === 'undefined') {
return;
}
let i;
let l;
if (typeof obj !== 'object') {
obj = [obj];
}
if (isArray(obj)) {
for (i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj);
}
} else {
const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
const len = keys.length;
let key;
for (i = 0; i < len; i++) {
key = keys[i];
fn.call(null, obj[key], key, obj);
}
}
}
trim 去除首尾空格
const trim = (str) => str.trim ?
str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
findKey 查找对象中的key属性
function findKey(obj, key) {
key = key.toLowerCase();
const keys = Object.keys(obj);
let i = keys.length;
let _key;
while (i-- > 0) {
_key = keys[i];
if (key === _key.toLowerCase()) {
return _key;
}
}
return null;
}
toCamelCase 转换为驼峰命名
const toCamelCase = str => {
return str.toLowerCase().replace(/[_-\s]([a-z\d])(\w*)/g,
function replacer(m, p1, p2) {
return p1.toUpperCase() + p2;
}
);
};
知识拓展
Object.getOwnPropertyNames vs Object.keys
Object.getOwnPropertyNames返回的是对象所有自己的属性,而Object.keys(obj)则返回的是所有可枚举属性,也就是属性下的enumerable: true
URLSearchParams
URLSearchParams接口定义了一些实用的方法来处理 URL 的查询字符串,内置了一些常用API,详情参考 URL地址技能