学习源码,可以帮助我们工具基础知识点和提升编程能力。之前分享过vue3中的常用工具函数(戳此链接)。
那今天本文的主角是axios源码中的/lib/utils.js,介绍一下axios库中常用的工具函数
axios/lib/utils.js
共用的toString 方法
var toString = Object.prototype.toString;
和vue3源码中判定一样
function isArray(val) {
return Array.isArray(val);
}
function isString(val) {
return typeof val === 'string';
}
function isNumber(val) {
return typeof val === 'number';
}
注意在js中,null
也是一个特殊对象,此时判定要排出null的情况。
此方法同vue3源码中判定对象方法
function isObject(val) {
return val !== null && typeof val === 'object';
}
纯对象: 用{}或new Object()创建的对象。
此方法同vue3源码中判定纯对象方法
function isPlainObject(val) {
if (toString.call(val) !== '[object Object]') {
return false;
}
// Object.getPrototypeOf返回指定对象的原型
// 其实就是判断目标对象的原型是不是`null` 或 `Object.prototype`
var prototype = Object.getPrototypeOf(val);
return prototype === null || prototype === Object.prototype;
}
测试代码如下
// 例子1
const o = {name: 'jay}
isPlainObject(o) // true
// 例子2
const o = new Object()
o.name = 'jay'
isPlainObject(o) // true
// 例子3
function C() {}
const c = new C()
isPlainObject(c); // false
function isUndefined(val) {
return typeof val === 'undefined';
}
function isFunction(val) {
return toString.call(val) === '[object Function]';
}
在vue3中该方法如下:
export const isFunction = (val: unknown) => typeof val === 'function'
两种方法比较:
测试代码如下:
// 1、普通function函数
let a = function(){console.log(1)};
console.log(typeof a); // function
console.log(Object.prototype.toString.call(a)); // '[object Function]'
// 2、赋值到变量的函数
let b = function(){console.log(1)};
console.log(typeof b); // function
console.log(Object.prototype.toString(b)); // '[object Object]'
// 3、ES6 class
class C{}
console.log(typeof C); // function
console.log(Object.prototype.toString.call(C)); // '[object Object]'
function isDate(val) {
return toString.call(val) === '[object Date]';
}
vue3中该方法如下:
export const isDate = (val: unknown) => val instanceof Date
两种方法对比:
typeof
~~ ,因为会返回object
new Date()
,通过new关键字创建的可以使用instanceof
(instanceof
运算符用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上)判定。同时toString方法也可以准确得到'[object Date]'
function isFile(val) {
return toString.call(val) === '[object File]';
}
function isBlob(val) {
return toString.call(val) === '[object Blob]';
}
// 最终是通过Buffer.isBuffer()方法去判定
function isBuffer(val) {
return val !== null
&& !isUndefined(val) // 先判断不是 `undefined`和`null`
&& val.constructor !== null
&& !isUndefined(val.constructor) // 再判断 `val`存在构造函数,因为`Buffer`本身是一个类
&& typeof val.constructor.isBuffer === 'function'
&& val.constructor.isBuffer(val); // 最后判定构造函数Buffer有`isBuffer`方法,并且用自身`isBuffer`判断
}
测试代码如下:
const buf = Buffer.from([1, 2, 3]);
console.log(typeof buf) // object
console.log(buf instanceof Buffer); // true
console.log(buf.constructor.isBuffer(buf)) // true
function isArrayBuffer(val) {
return toString.call(val) === '[object ArrayBuffer]';
}
function isFormData(val) {
return toString.call(val) === '[object FormData]';
}
测试代码:
let form = new FormData();
form.append('namme',12);
Object.prototype.toString.call(form)
'[object FormData]'
isObject
、isFunction
为上文提到的方法。function isStream(val) {
return isObject(val) && isFunction(val.pipe);
}
function isURLSearchParams(val) {
return toString.call(val) === '[object URLSearchParams]';
}
测试代码如下
const paramsString = "name=mj&age=13"
const searchParams = new URLSearchParams(paramsString);
console.log(isURLSearchParams(searchParams)) // true
trim
方法不存在的话,用正则匹配function trim(str) {
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
}
/**
*
* This allows axios to run in a web worker, and react-native.
* Both environments support XMLHttpRequest, but not fully standard globals.
* * web workers:
* typeof window -> undefined
* typeof document -> undefined
* * react-native:
* navigator.product -> 'ReactNative'
* nativescript
* navigator.product -> 'NativeScript' or 'NS'
*/
function isStandardBrowserEnv() {
if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
navigator.product === 'NativeScript' ||
navigator.product === 'NS')) {
return false;
}
return (
typeof window !== 'undefined' &&
typeof document !== 'undefined'
);
}
function forEach(obj, fn) {
// Don't bother if no value provided。若值不存在,无需处理,直接返回
if (obj === null || typeof obj === 'undefined') {
return;
}
// Force an array if not already something iterable。如果不是对象类型,强制转成数组类型
if (typeof obj !== 'object') {
obj = [obj];
}
if (isArray(obj)) {
// Iterate over array values。是数组,for循环执行回调fn
for (var i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj);
}
} else {
// Iterate over object keys。是对象,for in循环执行回调fn
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
fn.call(null, obj[key], key, obj);
}
}
}
}
function merge(/* obj1, obj2, obj3, ... */) {
var result = {};
function assignValue(val, key) {
if (isPlainObject(result[key]) && isPlainObject(val)) {
result[key] = merge(result[key], val);
} else if (isPlainObject(val)) {
result[key] = merge({}, val);
} else if (isArray(val)) {
result[key] = val.slice();
} else {
result[key] = val;
}
}
for (var i = 0, l = arguments.length; i < l; i++) {
forEach(arguments[i], assignValue);
}
return result;
}
function extend(a, b, thisArg) {
forEach(b, function assignValue(val, key) {
// 判断传入了上下文对象,以及 b 中 属性值val 是方法,则需要绑定函数执行上下文对象
if (thisArg && typeof val === 'function') {
a[key] = bind(val, thisArg); // 绑定函数的执行上下文对象
} else {
// 若并未传入上下文对象,或者不是函数,直接赋值
a[key] = val;
}
});
return a;
}
严
的 Unicode码
是4E25
,UTF-8
编码是E4B8A5
,两者是不一样的。它们之间的转换可以通过程序实现。function stripBOM(content) {
if (content.charCodeAt(0) === 0xFEFF) {
content = content.slice(1);
}
return content;
}
本文介绍了一些utils.js
中的非常实用的工具函数;相信通过阅读源码,日积月累,并把这些代码或思想应用的自己项目中去,相信能够很好的提升自己的编码能力。
prototype
属性是否出现在某个实例对象的原型链上