likes
comments
collection
share

我发现了axios源码工具函数中的一个小bug

作者站长头像
站长
· 阅读数 48

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

大家好,我是 那个曾经的少年回来了。10年前我也曾经年轻过,如今已步入被淘汰的年龄,但如下幡然醒悟,所以活在当下,每天努力一点点,来看看2024年的时候自己会是什么样子吧,2024年的前端又会是什么样子,而2024年的中国乃至全球又会变成什么样子,如果你也有想法,那还不赶紧行动起来。期待是美好的,但是更重要的是要为美好而为之奋斗付诸于行动。

最近在读axios的源码,有一些晦涩难懂,于是乎就先来入手一下 axiosutils 工具函数, 于是有趣的事情发生了。接下来就跟随我的思路来看看我发现的小问题吧,如果是大佬,就此别过。

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。

parseIntparseFloat是将字符串转换为数值,从第一个字符(位置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
评论
请登录