我发现了axios源码工具函数中的一个小bug
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情。
大家好,我是
那个曾经的少年回来了
。10年前我也曾经年轻过,如今已步入被淘汰的年龄,但如下幡然醒悟,所以活在当下,每天努力一点点,来看看2024年的时候自己会是什么样子吧,2024年的前端又会是什么样子,而2024年的中国乃至全球又会变成什么样子,如果你也有想法,那还不赶紧行动起来。期待是美好的,但是更重要的是要为美好而为之奋斗付诸于行动。
最近在读axios的源码,有一些晦涩难懂,于是乎就先来入手一下 axios
的 utils
工具函数, 于是有趣的事情发生了。接下来就跟随我的思路来看看我发现的小问题吧,如果是大佬,就此别过。
1、两个箭头函数的演绎
const typeOfTest = type => thing => typeof thing === type;
最开始我一看很蒙蔽,很多时候自己并不会去写这样的函数,说白了还是自己代码底子不行。可能很多大佬一看就明白了,所以基础很重要,基础很重要,基础很重要。箭头函数算是ES6中新增的。
那我先来一个最简单的箭头函数
const f = v => v;
// 等同于
const f = function (v) {
return v;
};
相信有点JavaScript基础的朋友们应该都能看懂上面的代码,所以参考上面的小例子,来类比一下
const typeOfTest = function(type) {
// 也就是把第一个箭头函数后面全部返回即可
return thing => typeof thing === type;
}
这个样子我相信很多人都能看明白了,不过此时我们还可以再次拆解,将两个箭头函数都用ES5的写法改写
let typeOfTest = function(type) {
return function(thing) {
return typeof thing === type;
}
}
再次看上面的代码,就再清楚不过了,其实发现调用typeOfTest会返回一个函数,那么就说明调用完之后还需要调用执行,而且再次调用还需要传入一个参数
typeOfTest('undefined')(undefined)
2、函数本身的意义
这里其实就是第一次调用先传入一个已知的数据类型,第二次调用再传入参数值,通过 typeof
解析出类型与第一次传入类型进行判断,返回 true
或者 false
。
所以就有了axios源码 utils.js
文件中一系列的函数
// 判断是否为undefined的方法
const isUndefined = typeOfTest('undefined');
// 判断是否为字符串的方法
const isString = typeOfTest('string');
// 判断是否为函数的方法
const isFunction = typeOfTest('function');
// 判断是否为Boolean类型的方法
const isBoolean = thing => thing === true || thing === false;
// 我觉得可以添加一个
const isBoolean = typeOfTest('boolean');
// 判断是否为数值类型的方法
const isNumber = typeOfTest('number');
这里我故意将 isNumber
放到最后。
这里其实就是我发现axios中一个小bug。
3、判断是否是number的问题
typeof NaN
的时候,其实返回的也是 number
。
NaN ,可以翻译为 not a number ,即不是一个数字。 NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),常用来指出数字类型中的错误情况,即:“执行数学运算没有成功,这是返回的结果” 所以有时候我们判断的时候可能要通过 Number.isNaN,而 Number.isNaN 是 ES6 中新增的函数,Number.isNaN()只有对于 NaN 才返回 true,非 NaN 一律返回 false。
所以上面判断是否为number数值的方法做一个小的调整,先判断一下是否为NaN
const isNumber = (thing) => Number.isNaN(thing)? false: typeOfTest('number')(thing)
这里还要关注一下 IsNaN 方法,和 Number.isNaN 的区别 juejin.cn/post/684490…。
isNaN(NaN); // true
isNaN('A String'); // true
isNaN(undefined); // true
isNaN({}); // true
Number.isNaN('A String'); // false
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN(NaN); // true
我想只有Number.isNaN(NaN)
是我们想要的结果,所以简单的来说 isNaN
方法算是之前JavaScript遗留的 bug 吧,然后 ES6 新增了 Number.isNaN,这个问题从而得到了解决。
4、哪些情况会导致NaN值的产生呢
Number(NaN) // NaN
Number(undefined) // NaN
Number('abc') // NaN
Number('null') // 0
Number('2.45s') // NaN
parseFloat(NaN) // NaN
parseFloat(undefined) // NaN
parseFloat(null) // NaN
parseFloat('abc') // NaN
parseFloat('2.45s') // 2.45
parseInt(NaN) // NaN
parseInt(undefined) // NaN
parseInt(null) // NaN
parseInt('abc') // NaN
parseInt('2.45s') // 2
1+NaN // NaN
1+undefined // NaN
1+null // 1
其实上面要注意一下 Number(null)
的值为0,并且 1+null
的值为 1。
parseInt
和 parseFloat
是将字符串转换为数值,从第一个字符(位置0)开始解析每个字符。而且也是一直解析到末尾,或者解析到遇见一个无效数字或者无效的浮点数字字符为止。
而 Number
可以将任意类型的字符转换为数值类型,根据具体类型进行输出判断,主要的几种判断方式我在上面已经列出。
5、判断是否是对象的方法
但是我发现判断是否是一个对象,这个判断axios倒是特意做了一个判断
const isObject = (thing) => thing !== null && typeof thing === 'object';
typeof null 输出 object:null 作为一个基本数据类型为什么会被 typeof 运算符识别为 object 类型呢?这个 bug 是第一版 Javascript 留下来的,javascript 中不同对象在底层都表示为二进制,而 javascript 中会把二进制前三位都为 0 的判断为 object 类型,而 null 的二进制表示全都是 0,自然前三位也是 0,所以执行 typeof 时会返回 'object'。 ----引用自《你不知道的 javascript(上卷)》
6、总结
-
typeof 作为类型判断的两个缺陷
- 判断是否为number类型,要将NaN考虑进去
- 判断是否为object类型,要将null考虑进行
-
箭头函数嵌套的解析,将复杂问题简单化
-
如果不使用typeof判断类型,可以考虑使用
Object.prototype.toString
这也是axios
中使用的一种方式。 -
了解
typeof NaN
输出number的问题 -
了解
typeof null
输出object的问题
我的个人博客:vue.tuokecat.com/blog
我的个人github:github.com/aehyok
我的前端项目:pnpm + monorepo + qiankun + vue3 + vite3 + 工具库、组件库 + 工程化 + 自动化 不断完善中,整体框架都有了 在线预览:vue.tuokecat.com github源码:github.com/aehyok/vue-…
转载自:https://juejin.cn/post/7140049846542532645