源码共读活动:第19期 | axios 工具函数
仓库:axios,在线查看
学习目标
- 初步学会看源码
- 学会 axios 中的10多个工具函数
前言
axios的工具函数主要是用于各种数据类型的判断,以及对数据进行二次处理,如下便是所有的工具函数:
1 | module.exports = { |
前置知识
因为大部分工具函数都是用于类型判断,所以先了解typeof
、instanceof
、Object.prototype.toString
等的用法很有必要。
数据类型 “7+1”
7 种原始类型(不可变): Boolean
、Undefined
、Number
、String
、Null
、Symbol(ES6)
、BigInt(ES6)
1 种对象类型Object
: 包含了Function
、Array
、特殊对象(RegExp
、Date
)
typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型
typeof
一般用来判断原始数据类型,但无法精准判断是哪一种对象。
1 | // 1、数值 |
特殊场景:
1 | // 历史遗留问题,bug变feature |
为什么null
是Object
,参考这篇文章:为什么typeof null的结果是Object?
主要和机器码标识的二进制值有关系,对象是000,null
也全是0,就这么被判断错了。
数据类型 | 机器码标识 |
---|---|
对象(Object) | 000 |
整数 | 1 |
浮点数 | 010 |
字符串 | 100 |
布尔 | 110 |
undefined | -2^31(即全为1) |
null | 全为0 |
instanceof
1 | // instanceof |
instanceof的原理
如果A属性沿着原型链能找到B.prototype,那么A instanceof B为true
原理伪代码:
1 | //方法一: |
constructor
用constructor
进行类型判断比较少用到,但也是种方法,列一下:
1 | (123).constructor === Number //true |
Object.prototype.toString
toString
是Object
原型对象上的一个方法,该方法默认返回其调用者的具体类型,是 toString
运行时this
指向的对象类型, 返回的类型格式为[object,xxx]
,xxx
是具体的数据类型。Object.prototype.toString
能精准的判断出所有数据类型。
1 | Object.prototype.toString.call(null) //"[object Null]" |
类型判断工具函数:
1 | // Array Number…… |
原始类型判断
原始类型基本用typeof
就能搞定判断。
isString:判断是否是字符串
1 | function isString(val) { |
isNumber:判断是否是数字
1 | function isNumber(val) { |
isUndefined:判断是否是undefined
1 | function isUndefined(val) { |
对象类型判断
一般使用Object.prototype.toString
进行对象类型判断。
1 | // 先提取toString函数 |
isObject:判断是否是对象
由于typeof null
的判断结果也是object
,所以要先进行排除。
1 | function isObject(val) { |
isPlainObject:判断是否是纯对象
纯对象概念:用{}
或new Object()
创建的对象,即该对象的原型是Object。
那么像自定义构造函数或者class
new
创建出来的对象就不是纯对象了,因为它们的原型不是Object。
1 | /** |
isArray:判断数组
instanceof
和 isArray
:当检测Array
实例时, Array.isArray
优于instanceof
,因为Array.isArray
能检测iframes
。(文档)
1 | // 新判断方式 |
isArray
的判断方式发生了改变,参考其他组员的文章:
与这个改动相关的 PR 提到这是面向未来 ECMAScript 规范的更改,以及提供性能优势,并且通常更清晰。
Polyfill:
1 | if (!Array.isArray) { |
isArrayBuffer:判断ArrayBuffer
ArrayBuffer
:通用的、固定长度的原始二进制数据缓冲区
1 | function isArrayBuffer(val) { |
isBuffer:判断是否是Buffer
- 判断是否为空
- 判断是否有构造函数
constructor
- 最后通过
isBuffer
来判断数据类型上文罗列过JS中的数据类型,其中并没有二进制数据,但在实际开发中,会用到二进制数据,例如下载图片等操作,那么就需要一个专门存放二进制数据的缓存区。1
2
3
4
5
6
7function isBuffer(val) {
return
val !== null && !isUndefined(val)
&& val.constructor !== null && !isUndefined(val.constructor)
&& typeof val.constructor.isBuffer === 'function'
&& val.constructor.isBuffer(val);
}
参考文档:Node.js中文网或者菜鸟教程isFormData:判断是否是FormData
文档1
2
3function isFormData(val) {
return toString.call(val) === '[object FormData]';
}isArrayBufferView:判断是否是ArrayBufferView
是一个表示以下任意一个 TypedArray 类型的辅助数据类型1
2
3
4
5
6
7
8
9function isArrayBufferView(val) {
var result;
if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
result = ArrayBuffer.isView(val);
} else {
result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
}
return result;
}isDate:判断是否是Date
1
2
3function isDate(val) {
return toString.call(val) === '[object Date]';
}isFile:判断是否是文件类型
1
2
3function isFile(val) {
return toString.call(val) === '[object File]';
}isBlob:判断是否是Blob
1
2
3function isBlob(val) {
return toString.call(val) === '[object Blob]';
}isFunction:判断是否是函数
1
2
3function isFunction(val) {
return toString.call(val) === '[object Function]';
}isStream:判断是否是流
1
2
3function isStream(val) {
return isObject(val) && isFunction(val.pipe);
}
API判断
isURLSearchParams:判断是否是URLSearchParams
URLSearchParams
接口定义了一些实用的方法来处理URL
的查询字符串。
1 | function isURLSearchParams(val) { |
1 | var paramsString = "q=URLUtils.searchParams&topic=api" |
isStandardBrowserEnv:判断是否是标准浏览器环境
官方已废弃navigator.product
属性。
1 | function isStandardBrowserEnv() { |
其他
forEach:遍历对象或数组
1 | /** |
- 如果入参是
null
或者undefined
,函数直接退出,默认返回undefined
;- 如果入参不是对象类型(数组也是对象类型中的一种,
typeof [] === 'object'
),则包裹入参使其成为数组类型;- 如果是数组,回调函数将会传入每个元素的值,索引和源数组;
- 如果是对象,回调函数将会传入每个可枚举属性的值,属性名和源对象。
forEach
方法封装了数组和对象的遍历,感觉会很有用。看讨论说内部遍历数组不用原生forEach
是为了兼容IE11,但我查了下从IE9开始就可以使用了。不过论兼容性和性能的话,还是比不了for循环的吧。
merge:合并对象
1 | /** |
其他合并对象工具函数:
使用了deepmerge
这个库。
1 | const merge = require('deepmerge'); |
extend:继承对象进行拓展
对象a继承对象b的属性
1 | /** |
trim:去除首尾空格
1 | function trim(str) { |
stripBOM:删除UTF-8编码中BOM
BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。
1 | function stripBOM(content) { |
总结
虽然是axios
的工具函数库,但以后在项目中碰到类似的判断,可以直接参考使用。
以上涉及到的类型判断很多,但只要掌握了typeof
、Object.prototype.toString
等的基本用法,就能举一反三。