首页 > 编程语言 >读了会 axios 源码,虽然云里雾里,但是我想到了三个有趣的对比

读了会 axios 源码,虽然云里雾里,但是我想到了三个有趣的对比

时间:2023-06-10 10:36:19浏览次数:67  
标签:云里雾里 axios const log Object 源码 toString console delete

源码阅读

最近翻来了 axios 源码,信心满满的看了会,虽然哪跟哪都没串起来,但是意外收获了一些新的想法。

有几组不错的知识点,对比看,比单独看每个知识点,更有趣一些。

遇到有趣的知识点,当然要分享一下。

文章速读

本文从 axios 的源码联想到了几个不错的知识点对比。

阅读文章,可以有以下收获:

读了会 axios 源码,虽然云里雾里,但是我想到了三个有趣的对比_源码

知识点对比开始

delete or undefined, 谁是更好的选择?

技术讨论小剧场

一:这里为什么要用 delete 删除这个属性。

某:因为异步请求里不能带上这个属性。

一:把值设置成 undefined,JSON.stringify 方法会过滤掉值为 undefined 的对象属性。

某:这个方法好像挺不错的。等等,我要是没有用到 JSON.stringify 方法呢?

一:写个判断方法。

某:键盘已递上。

undefined 值的判断方法

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

/**
 * Determine if a value is undefined
 *
 * @param {*} val The value to test
 *
 * @returns {boolean} True if the value is undefined, otherwise false
 */
const isUndefined = typeOfTest('undefined');

const val = undefined;
const val2 = 2;
isUndefined(val) // true
isUndefined(val2) // false

某: 怎么写的这么快!

一:当然了,这可是 axios 源码里采用的方法。

某:所以结论就是,推荐将对象的值设置为 undefined,而不是delete 它。

一:是的。

某:再讲点 delete 的知识点。这个操作符,我还不太熟悉。

一:这个可以有。正好可以正向思维和逆向思维齐上阵。

delete 删除了什么?

删除对象的某个属性

我们会按照 MDN 文档定义的那样,「delete 操作符用于删除对象的某个属性」,先来尝试删除对象的属性:

var obj = {
  name: 'ye',
  age: 18,
};
delete obj.age;
console.log(delete obj.age); // true
console.log(obj); // { name: 'ye' }

非常符合预期的结果,delete 返回值是 true,且 obj 已不存在 age 属性。

如果删除一个对象不存在的属性,会怎样?
var obj = {
  name: 'ye',
  age: 18,
};
delete obj.desc;
console.log(delete obj.desc); // true
console.log(obj); // { name: 'ye', age: 18 }

这种情况也很好解释,MDN 官网已经给了文字解释:

如果你试图删除的属性不存在,那么 delete 将不会起任何作用,但仍会返回 true。

delete 'zhang' or delete 18 结果会怎样?
console.log(delete 'zhang'); // true
console.log(delete 18); // true

结果都是 true,有意思。其实,这里的字符串也好,数字也好,其实是单值表达式的结果,delete 删除的是这个表达式的结果,所以返回了 true。

所谓单值表达式是指没有运算符的表达式,一般值是其本身。

删除 let 或 const 声明的属性会怎样?
var name = 'ye';
or 
var name = obj.name;
console.log(delete name); // false

结果是 false,因为任何用 let 或 const 声明的属性不能够从它被声明的作用域中删除。

小结

  1. 不需要某个对象属性时,推荐将对象的值设置为 undefined,而不是delete 它。
  2. 经过一系列实验会发现,delete 其实删除的是一个表达式的引用类型的结果。
  3. axios 源码内容虽然不是特别多,但是完整的梳理清楚还是挺耗时的。我帮大家画个入口示意图,感兴趣的可以下载到本地,慢慢赏析。☞axios github

读了会 axios 源码,虽然云里雾里,但是我想到了三个有趣的对比_源码_02

yield 和 return,这俩有故事?

技术讨论小剧场

一:为何眉头紧锁。

某:正在看 axios 的源码。

一:我理解了。

某:我不理解,这里为什么要用 yield。

一: 这么快看到这里了。

某:我只是先打开了这个文件而已。

品品为什么要用 yield

axios 源码里面有一段代码,在测试用例里面,实际的代码无法直接打印,我稍作了调整,如下:

const count = 10;
const chunkLength = 10;
const contentLength = count * chunkLength;
const samples = Array.from(
  (function* () {
    for (let i = 1; i <= 10; i++) {
      yield {
        loaded: chunkLength * i,
        total: contentLength,
        progress: (chunkLength * i) / contentLength,
        bytes: 4,
        download: true,
      };
    }
  })(),
);

打印 samples 的结果

某:如果这里的代码把 yield 改成 return 会怎样。

一:你猜。

不卖关子,其实会打印一个空数组。

console.log(samples); // []

某:能用 return 实现上面的截图中的数组吗?

一:当然可以。

某:键盘和膝盖双双奉上。

Array.from 支持通过伪数组对象创建数组对象。伪数组对象是指拥有一个 length 属性和若干索引属性的任意对象。

const count = 10;
const chunkLength = 10;
const contentLength = count * chunkLength;
const samples = Array.from({ length: count }, (_, j) => {
  let i = j + 1;
  return {
    loaded: chunkLength * i,
    total: contentLength,
    progress: (chunkLength * i) / contentLength,
    bytes: 4,
    download: true,
  };
});

yield 和 return 的故事

相同场景

这俩功能看着挺相似的,都能返回值给函数调用者。比如下面这两个代码块打印的结果是一样的。

使用 yield

function* foo(index) {
  while (index < 2) {
    index++;
    yield index;
  }
}

const iterator = foo(0);

console.log(iterator.next().value); // 1

使用 return

function* foo(index) {
  while (index < 2) {
    index++;
    return index;
  }
}

const iterator = foo(0);

console.log(iterator.next().value); // 1
如果把返回的这行代码提升会怎么样?

使用 yield

function* foo(index) {
  while (index < 2) {
    yield index;
    index++;
  }
}

const iterator = foo(0);

console.log(iterator.next().value); // 0
console.log(iterator.next().value); // 1

使用 return

function* foo(index) {
  while (index < 2) {
    return index;
    index++;
  }
}

const iterator = foo(0);

console.log(iterator.next().value); // 0
console.log(iterator.next().value); // undefined

结果不一样了。可见这俩有个明显的不同:

  • return 语句终止函数的执行。
  • yield 语句挂起当前函数,而下一次调用 next() 时,在 yield 之后紧接着的语句会继续执行
听说 yield 能传值?

来看下面这个例子

function* func(x) {
  console.log('x:', x);
  x--;
  x = yield x;
}
let generatorFunc = func(10);
let value = generatorFunc.next().value;
console.log('value:', value);

打印结果

x: 10 // 第一个console
value: 9 // 第二个console

解析一下,第一个 console,x 值来自函数的传参,这个很容易理解。第二个 console,这里 x 值来自调用 generatorFunc.next(arg) 时的传参 arg,而 arg 来自 yield 表达式的结果。

小结

  1. yield 关键字用于暂停和恢复生成器函数。
  2. yield 和 return 的故事在于,yield可以被认为是一个基于生成器的版本的 return 关键字。但是 yield 功能更丰富。
  3. axios 源码,看到哪里算哪里吧。

typeof and toString, 类型校验专场

技术讨论小剧场

某:还记得我们前面讨论的如何判断值为 undefined 吗?

一:当然,就在文章前面没多远的地方。

某:我又找到了一种判断方式。

一:替换方式?哪种更好?

某:我愿称之为 typeOfTest 的升级版。

toString:更辽阔的类型校验

先来看看 axios 源码是怎么实现对引用类型(其实包括基础类型)的校验。

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));

const kindOfTest = type => {
  type = type.toLowerCase();
  return thing => kindOf(thing) === type;
};
/**
 * Determine if a value is a Date
 *
 * @param {*} val The value to test
 *
 * @returns {boolean} True if value is a Date, otherwise false
 */
const isDate = kindOfTest('Date');

console.log(isDate(new Date())); // true
console.log(isDate('ye')); // false

上面的方法,核心在于使用 Object.prototype.toString.call() 获取数据类型,它返回 "[object Type]",使用正则匹配可以得到最终的 Type。

下面我们用 Object.prototype.toString.call() 打印一下绝大多数的数据类型,看结果否和我们预期的一样:

console.log(Object.prototype.toString.call(111)); // [object Number]
console.log(Object.prototype.toString.call('ye')); // [object String]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object ReUndefinedgExp]
console.log(Object.prototype.toString.call(Symbol())); // [object Symbol]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(function () {})); // [object Function]
console.log(Object.prototype.toString.call(new Error())); // [object Error]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(new RegExp())); // [object RegExp]
console.log(Object.prototype.toString.call(Map)); // [object Function]
console.log(Object.prototype.toString.call(Math)); // [object Math]

可以得到几乎所有的数据类型。

小结

  1. Object.prototype.toString.call() 几乎可以实现所有数据类型的校验。
  2. 想要获取准确的数据类型,还要在 [object Type] 的基础上通过正则匹配获取最终的 Type。
  3. 方法都是现成的,需要哪个用哪个。掌声送给 axios 源码。

总结

整个 axios 源码相较而言,不算特别多,但是想要全部梳理明白,还是需要一定的时间和精力的。不过,从一些工具函数文件出发,很容易吸收部分功能设计,比如 util 文件。

本文从 axios 源码中的功能结合日常开发,总结了三个有趣的对比实验,希望能对今后的开发有帮助。

标签:云里雾里,axios,const,log,Object,源码,toString,console,delete
From: https://blog.51cto.com/u_15838863/6454107

相关文章

  • JAVA的springboot+vue家政服务管理平台,家政预约管理系统,附源码+数据库+论文+PPT
    1、项目介绍随着家政服务行业的不断发展,家政服务在现实生活中的使用和普及,家政服务行业成为近年内出现的一个新行业,并且能够成为大众广为认可和接受的行为和选择。设计家政服务管理平台的目的就是借助计算机让复杂的销售操作变简单,变高效。家政服务管理平台采用了B/S结构,JAVA作......
  • 基于Python+tkinter+pygame的音乐播放器完整源码
    importosimporttkinterimporttkinter.filedialogimportrandomimporttimeimportthreadingimportpygamefolder=''defplay():#folder用来表示存放MP3音乐文件的文件夹globalfoldermusics=[folder+'\\'+musicfo......
  • Taro源码 Taro DOM
    浏览器的事件系统是Web应用程序中必不可少的部分,可以使开发人员通过编写事件监听器来响应用户操作、处理网络请求等实现交互性和动态性的Web应用程序。Taro作为支持一码多端的跨端框架,支持支付宝小程序、微信小程序、h5等多个平台。为了抹平端上差异,同时支持小程序平台也能够使......
  • 直播源码开发,使用动画设置ProgressBar进度
    直播源码开发,使用动画设置ProgressBar进度布局文件: <?xmlversion="1.0"encoding="utf-8"?><LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:app="http://schemas.android.com/apk/res-auto"  ......
  • 直播商城源码,点击复制功能和长按复制功能
    直播商城源码,点击复制功能和长按复制功能一、点击复制+长按复制效果 index.wxml 注意:data-title=我是被复制的文本内容<textselectable="true">我是被复制的文本内容/text><viewbindtap="copyBtn"data-title="{{title}}">复制</view>index.js  //不使用封装方法  ......
  • 直播平台搭建源码,LintCode 大小写转换
    直播平台搭建源码,LintCode大小写转换一、直接利用C++中的tolower(大写转小写)函数。 classSolution{public:  /**   *@paramstr:theinputstring   *@return:Thelowercasestring   */  stringtoLowerCase(string&str){    //Wri......
  • UE5 源码编译开发注意事项
    工程清理编译 针对UE5源码版,项目级别的清理步骤:(1)删除项目根目录中:Binaries、Build、DerivedDataCache和Intermediate文件夹,以及sln文件。(2)通过.uproject重新生成VisualStudio项目文件,此步骤会重新生成sln文件和Intermediate文件夹。(3)打开sln项目解决方案,将自建项......
  • [spring-boot] 源码解读#org.springframework.boot.ApplicationArguments [转发]
    1ApplicationArguments概述1.1简述org.springframework.boot.ApplicationArguments接口提供对用于运行org.springframework.boot.SpringApplication的参数访问。ApplicationArguments接口只有一个实现类DefaultApplicationArguments。1.2使用示例示例1@SpringBootA......
  • 海外直播源码技术文字聊天功能的配置
    今天我要分享的知识和我们日常生活中常用到的一个东西有关,它就是文字。目前已知发现我国最早的文字是距今5000多年的甲骨文,随着历史的发展,文字也在不断的发展,一直发展到我们现在所使用的文字。网络时代的到来,让文字进入到了网络中,在网上我们可以用文字去写文章、搜索问题、聊天等,其......
  • 海外直播源码技术文字聊天功能的配置
     今天我要分享的知识和我们日常生活中常用到的一个东西有关,它就是文字。目前已知发现我国最早的文字是距今5000多年的甲骨文,随着历史的发展,文字也在不断的发展,一直发展到我们现在所使用的文字。网络时代的到来,让文字进入到了网络中,在网上我们可以用文字去写文章、搜索问题、聊天......