Skip to content

两个箭头函数的演绎

const typeOfTest = type => thing => typeof thing === type;

最开始一看很蒙蔽,很多事情自己不会写这样的代码,说白了还是代码底子不行。可能很多大佬一看就明白了。 先来一个最简单的箭头函数

javascript
const f = v => v;

// 等同于
const f = function (v) {
  return v;
};

所以我们来类比一下

javascript
var typeOfTest = function(type) {
  // 也就是把第一个箭头函数后面全部返回即可
  return thing => typeof thing === type;
}

这个样子我相信很多人都能看明白了,再进行一步的解析就完事了

javascript
var typeOfTest = function(type) {
  return function(thing) {
    return typeof thing === type;
  }
}

再来看一下,其实发现调用typeOfTest会返回一个函数,那么就说明调用完之后还需要调用执行

javascript
// 这里其实就是
typeOfTest('undefined')(undefined)

所以就用了下面一系列的函数,这是axios utils.js中的

javascript
// 判断是否为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');

// 判断是否为一个object对象
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(上卷)》

所以axios在判断是否为对象的时候,先判断是否等于null,再进行typeof的比对。

| 这里其实我发现了axios的一个小bug。typeof NaN的时候,其实返回的也是number.

NaN ,可以翻译为 not a number ,即不是一个数字。 NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),常用来指出数字类型中的错误情况,即:“执行数学运算没有成功,这是返回的结果” 所以有时候我们判断的时候可能要通过 Number.isNaN,而 Number.isNaN 是 ES6 中新增的函数,Number.isNaN()只有对于 NaN 才返回 true,非 NaN 一律返回 false。

| 这里还要关注一下 IsNaN 方法,和 Number.isNaN 的区别 https://juejin.cn/post/6844903507368083469,简单来说 isNaN 之前算是 bug 吧,然后 ES6 新增了 Number.isNaN。

所以上面判断是否为number数值的方法做一个小的调整,先判断一下是否为NaN

const isNumber = (thing) => Number.isNaN(thing)? false: typeOfTest('number')(thing)

拆解第二个两个箭头函数

javascript
//这个在顶部单独拎出来的
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));

首先提一下 Object.create(null) 就是生成一个空的对象 {},创建完kindOf后先传入了一个空对象进行IIFE自执行闭包,cache 由字面意思便可以看出来缓存的意思,也就是传进来的空对象,在执行完闭包之后,cache就一直存在了不会释放掉,也就由了缓存的意思。

| 如果你想进一步了解一下闭包,我之前有整理过一篇非常容易理解的文章可以看一下:https://juejin.cn/post/7120371754274553887

再来看一下Object.prototype.toString

javascript
Object.prototype.toString.call(null); //  '[object Null]'

Object.prototype.toString.call(undefined); //'[object Undefined]'

Object.prototype.toString.call(123); //'[object Number]'

Object.prototype.toString.call(123n); //'[object BigInt]'

Object.prototype.toString.apply("123"); //'[object String]'

Object.prototype.toString.apply(true); //'[object Boolean]'

Object.prototype.toString.apply(Symbol()); //'[object Symbol]'

Object.prototype.toString.apply({}); // '[object Object]'

Object.prototype.toString.apply([]); // '[object Array]'

Object.prototype.toString.apply(new Date()); // "[object Date]"

Object.prototype.toString.apply(new Function()); // "[object Function]"
Object.prototype.toString.apply(function t() {}); // '[object Function]'

Object.prototype.toString.apply(Math); // '[object Math]'

Object.prototype.toString.apply(new RegExp()); //'[object RegExp]'

通过我的console打印可以非常明确的看到类型标注,这也是上面为什么使用了slice(8, -1)

javascript
const kindOf = function (cache) {
  return function (thing){
    const str = toString.call(thing);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
})(Object.create(null));

这样再来看这个函数,就非常的清晰了,这里截取了[object Array] Array, 从第八位字符串开始到最后。 所有最后总结这个kindOf函数的作用便是,传入一个值,输出一个类型。

再来看一下下面的调用示例

const kindOfTest = (type) => {
  type = type.toLowerCase();
  return (thing) => kindOf(thing) === type
}

这个函数相对来说就比较好理解,一个箭头函数里面开始执行,第二行最终又返回一个箭头函数。 其实意思便是先传入一个类型,再通过返回的函数,传入某个参数,来判断参数的类型是否与type一致。

javascript
// 判断是否为RegExp类型的方法
const isRegExp = kindOfTest('RegExp');

// 判断是否为日期类型的方法
const isDate = kindOfTest('Date');

// 判断是否为ArrayBuffer类型
const isArrayBuffer = kindOfTest('ArrayBuffer');

// 判断是否为文件类型的方法
const isFile = kindOfTest('File');

// 判断是否为Blob类型的方法
const isBlob = kindOfTest('Blob');

// 判断是否为文件列表类型 FileList的方法
const isFileList = kindOfTest('FileList');

// 判断是否为URLSearchParams类型的方法
const isURLSearchParams = kindOfTest('URLSearchParams');

// 判断是否为HTMLFormElement类型的方法
const isHTMLForm = kindOfTest('HTMLFormElement');

数组相关方法

  • 判断是否为数组的方法

直接使用Array数组本身中的方法

javascript
const {isArray} = Array;