67行JS代码实现队列取代数组,面试官刮目相看

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外:目前建有江西|湖南|湖北籍前端群,可加我微信进群。

这是来自源码共读群中大二的小伙伴投稿,写的非常好,图文并茂,关键还写了好多篇笔记了。原文链接可点击文末阅读原文查看。

Part11. 前言

1.1 这个库,是干啥的

如果你项目中要用到一个非常大的数组,并且你经常需要使用这两个操作:

  • Array.push() 在末端添加一个元素.

  • Array.shift()在取出队列首端的一个元素,整个队列往前移,这样原先排第二的元素现在排在了第一

如果学过数据结构,就会敏锐地发现,诶这两个操作,不就是在模拟队列

queue 队列是一个有序的元素列表,其中一个元素插入到队列的末尾,然后从队列的前面移除。队列的工作原理是**先进先出(FIFO)**。

JS 没有queue这个数据结构,用数组模拟就好了,真方便!
nonono,回到开头,当数据量较小的时候,似乎没什么影响,但如果数据量较大,性能就会严重下降
这是因为在底层实现中,数组是顺序存储的,当你shift的时候,会先取出队列首端的一个元素,整个队列往前移——整个操作的事件时间复杂度是**O(n)**
如果你的项目正如上面我所说的情况,那么你很可能就需要这个包 yocto-queue,它能让你的shift操作时间复杂度降为O(1)。(在这库里面shift用的是dequeue方法)

1.2 你能学到

  • ES6 中的 class

  • 链表和数组的区别,时间复杂度

  • JS 实现链表的方法

  • 学习 Symbol.iterator 的使用场景

  • 调试源码


Part22. 准备

2.1 了解API

import Queue from 'yocto-queue';const queue = new Queue();queue.enqueue('🦄');
queue.enqueue('🌈');console.log(queue.size);
//=> 2console.log(...queue);
//=> '🦄 🌈'console.log(queue.dequeue());
//=> '🦄'console.log(queue.dequeue());
//=> '🌈'

queue = new Queue()

The instance is an Iterable, which means you can iterate over the queue front to back with a “for…of” loop, or use spreading to convert the queue to an array. Don't do this unless you really need to though, since it's slow.

该实例是可枚举的,也就是说 你可以用for...of来遍历,并且可以用扩展运算符将其变为数组,但是尽量不要这样做,这样性能很差

.enqueue(value)

添加一个元素到队尾

.dequeue()

删去队头,并返回被删除的值 || 或者是 undefined(队列本来就已经为空的情况)

.clear()

清空队列

.size

返回队列的大小

Part33 看看  源码

3.1 环境准备

# 克隆官方仓库
git clone https://github.com/sindresorhus/yocto-queue.git
cd .\yocto-queue\
npm install
code .

3.3 调试源码

查看 package.json文件来确定主入口为 index.js

demo

新建文件夹examples,存放 demo index.js

// yocto-queue/examples/index.js
import Queue from "../index.js";const queue = new Queue(); //此处打断点
queue.enqueue("⛵");
queue.enqueue("🌊");console.log(queue.dequeue());console.log(queue.size);
for (let q of queue) {console.log(q);
}
queue.clear();

node examples/index.js或者直接F5也可以即可开始调试源码,其实这个代码复杂度不手动调试也可以的,但是通过调试可以让你很明确地看到哪一步代码用到了哪里的东西

3.4 理解源码

源码

Queue中,#head#tail可以视作虚拟结点,只是分别用来指向头和尾结点的。每次遍历的时候先找到头结点(#head指向的结点),然后通过每个结点的next指针往后走。即使只有头结点也能组成该链表——慢慢遍历总能到最后面,但是显然这样效率就低了,所以还有一个专门的尾指针#tail,方便尾部插入结点
源码总览:

class Node {value;next;constructor(value) {this.value = value;}
}export default class Queue {#head;#tail;#size;constructor() {this.clear();}enqueue(value) {const node = new Node(value);if (this.#head) {this.#tail.next = node;this.#tail = node;} else {this.#head = node;this.#tail = node;}this.#size++;}dequeue() {const current = this.#head;if (!current) {return;}this.#head = this.#head.next;this.#size--;return current.value;}clear() {this.#head = undefined;this.#tail = undefined;this.#size = 0;}get size() {return this.#size;}* [Symbol.iterator]() {let current = this.#head;while (current) {yield current.value;current = current.next;}}
}

分步解析

enqueue

queue.enqueue("⛵");时,会创造Queue中第一个实例node,第一个结点自然头和尾都指向他自己

if (this.#head) {//...
} else {this.#head = node;this.#tail = node;
}
59454edc3cc3ce98969c618f8fa8e859.png
image.png

queue.enqueue("🌊");随后我们添加第二个结点

if (this.#head) {this.#tail.next = node;this.#tail = node;
} else {//...
}

825b75ee8be957cfabbdf0a06ff19b5a.png
实际上我们可以发现,这就是尾插法

dequeue

console.log(queue.dequeue());

dequeue() {const current = this.#head;   //获取当前if (!current) {return;}this.#head = this.#head.next;this.#size--;return current.value;
}
a4b2874d957d2def34591d5300c7d1fb.png
image.png

size

console.log(queue.size);

get size() {return this.#size;
}

这里用到了 class 中 getters

⭐for...of

这里是本文的一个重点

这里实现了Queue这个对象可以通过for...of来进行遍历,即让它可以迭代。
想要让对象可迭代,需要添加一个Symbol.iterator方法,这个方法专门用来使对象可迭代的内建symbol
通过调试我们也可以知道,当进入for...of,他就会进入Symbol.iterator这个方法,(如果没找到,就会报错,像数组那些对象都是有内置该方法的),该方法必须返回一个迭代器—— 一个有next方法的对象。
像这样使用:

let range = {from: 1,to: 5,[Symbol.iterator]() { // 在 for..of 循环开始时被调用一次return {current: this.from,last: this.to,next() { // 每次迭代时都会被调用,来获取下一个值if (this.current <= this.last) {return { done: false, value: this.current++ };} else {return { done: true };}}};}
};for(let value of range) {alert(value); // 1,然后 2,然后 3,然后 4,然后 5
}

而源码中并不是这样的,而是这样:

* [Symbol.iterator]() {let current = this.#head; //通过current记录当前迭代进程while (current) {   //循环取值,直到没有yield current.value;  //取值,并返回current = current.next;//通过next往下一个走}
}

这是因为这里并不仅是使用了Symbol.iterator

⭐生成器

生成器是 ES6 新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力。这种能力具有深远的影响,比如使用生成器可以自定义迭代器和实现协程。

在函数前面加一个星号*,则表示它是一个生成器。调用生成器函数会产生一个生成器对象,其一开始处于暂停状态,该对象也实现了Iterator接口,通过调next()使其转为开始或者恢复执行状态。生成器函数在遇到yield关键字前会正常执行,遇到该关键字后,执行会停止,函数作用域的状态被保留 —— 有点像函数的中间返回语句,它能让函数返回一个值出去,但是函数仍能继续执行。随后通过在生成器对象上调用next方法恢复执行。
实际上,很少在生成器对象上显式调用next(),而是将其作为可迭代对象——

function* generatorFn(){yield 1;yield 2;yield 3;
}
for(let i of generatorFn()){console.log(i) 
}
//1
//2
//3

让我们回到源码中

for (let q of queue) {console.log(q);
}

结合上面对Symbol.iterator的理解

当进入for...of,他就会进入Symbol.iterator这个方法

也就是说 这样调用时,实际上就是

for (let q of queue[Symbol.iterator]()) {console.log(q);
}

[Symbol.iterator]这个函数变为了生成器函数,并将其作为可迭代对象!大大地减少了代码量~

clear

clear() {this.#head = undefined;this.#tail = undefined;this.#size = 0;
}

很简单,直接将头指针和尾指针指向的值改为undefinedsize也设置为0,剩下的就靠JS自身的垃圾回收机制了,本文就不涉及了。

Part44. 学习资源

  • 数组

  • class

  • Symbol.iterator

  • 垃圾回收机制

  • 红宝书 7.3 生成器

Part55. 总结 & 收获

  • 复习了 ES6 中的 class以及相关语法

  • 链表和数组的区别,时间复杂度,通过指针的空间 来省下按顺序遍历的时间——一种空间换时间的性能优化策略

  • JS 实现链表的方法,有了class这个语法后,和其他语言差不多了

    • Node结点,存当前value以及与用于相邻结点相连的指针

  • 复习 Symbol.iterator 的使用场景 以及 生成器这个平时可能用的较少的知识点

🌊如果有所帮助,欢迎点赞关注,一起进步⛵

7f9138272599097a394f23f27a12d39e.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经坚持写了8年,点击查看年度总结。
同时,最近组织了源码共读活动,帮助4000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

4de3a23c636241008fe1443a48ea0563.png

扫码加我微信 ruochuan02、拉你进源码共读

今日话题

目前建有江西|湖南|湖北 籍 前端群,想进群的可以加我微信 ruochuan12 进群。分享、收藏、点赞、在看我的文章就是对我最大的支持~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ux和ui_我怎么知道UI / UX是否适合我?

ux和ui重点 (Top highlight)I’m super excited to be writing this as it’s the first official issue of Visual Q’s! If you don’t already know, this will be a monthly advice column for designers. If you join the newsletter, you’ll receive this before it goe…

vs2017字体最佳选择_如何为下一个项目选择最佳字体? 一个简单的游戏

vs2017字体最佳选择“If I have the right font, half my design battle is already won!”“如果我使用正确的字体&#xff0c;那么我的设计大战已经赢了一半&#xff01;” In my first UX Design job, my AVP( Satish if you’re reading this, this one’s for you. ) onc…

浅谈初中级前端学习方法~

大家好&#xff0c;我是若川。 常有小伙伴问我如何学习前端开发。今天就简单谈下学习方法&#xff0c;方法可能主要适用于初中级前端。回想我们高中学习&#xff0c;是不是都是"以课本为主&#xff0c;其他资料为辅"。而且课堂上记笔记&#xff0c;然后通过大量练习&…

ui设计中的版式设计_设计中的版式-第3部分

ui设计中的版式设计and how not to suck at it以及如何不吸吮它 This is the 3rd and last part of the series. Here we take all our learnings from Part 1(Click to read) & Part 2(Click to read) and put to good use. Lets begin!这是本系列的第三部分也是最后一部…

听说你还在用开发者工具手动上传小程序,快来试试 miniprogram-ci 提效摸鱼

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

ucla ai_UCLA的可持续性:用户体验案例研究

ucla aiRole: UX Researcher / UX Designer / Critical-thinker角色&#xff1a; UX研究人员/ UX设计人员/批判性思维者 Scope: 4 weeks, March — March 2020范围&#xff1a; 4周&#xff0c;2020年3月至2020年3月 What I Did: UX Research, Speculative Design, Product D…

大三的小白同学是如何拿到字节offer的,经验分享

这是来自大三邵小白同学的投稿。原文链接&#xff1a;https://juejin.cn/post/7092806181856657445很多时候我们容易羡慕别人成功了&#xff0c;却往往没有看到别人背后的努力。1前言大家好&#xff0c;我是邵小白&#xff0c;一个长沙某不知名双非的大三学生。今年三月份来到杭…

UNIBO大学博物馆网络设计—品牌重塑和数字产品设计

Brief / Redesign the Visual Identity of the University of Bologna Museum Network (SMA) and apply the new designs to a Digital Product简介/重新设计博洛尼亚大学博物馆网络(SMA)的视觉识别&#xff0c;并将新设计应用于数字产品 Period / Mar 2020 — June 2020期间/…

进来做几道 JavaScript 基础题找找自信?

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

人物肖像速写_骄傲家庭:肖像项目

人物肖像速写2020 has been a solemn, transformative year. Pride month takes place in the context of a groundswell up-rising against racism and police brutality and in the continued isolation of COVID-19.2020年是庄严&#xff0c;变革的一年。 骄傲月的发生是在反…

答读者问:钱和成长,哪个更重要?

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

ui设计颜色的使用_UI设计中颜色使用的10条原则

ui设计颜色的使用重点 (Top highlight)1.颜色术语 (1. Color Terminology) Color terminology forms our foundation of color knowledge. Think of color terms like hue, tint, and shade as tools that we can employ to develop unique color palettes.颜色术语构成了我们颜…

Chrome插件:网易云音乐听歌识曲

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

如何设置ad18捕捉图标_图标设计中的像素捕捉

如何设置ad18捕捉图标More in the iconography series:• Foundations of Iconography• 7 Principles of Icon Design• 5 Ways to Create a Settings Icon• Icon Grids & Keylines Demystified• 3 Classic Icon FamiliesWe all want our designs to display sharp on a…

React Hooks 原理与最佳实践

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

插图 引用 同一行两个插图_为什么插图是产品的重要组成部分

插图 引用 同一行两个插图“Hi, my name is Ludmila and I’m a UX/UI designer”“嗨&#xff0c;我叫Ludmila&#xff0c;我是UX / UI设计师” “Hi, Ludmila”“嗨&#xff0c;路德米拉” “Welcome”“欢迎” Not anonymously at all, I’ve been doing UX/UI design fo…

如果是你你会如何重新设计和定义维基百科(wikipedia)?

日期&#xff1a;2012-8-11 来源&#xff1a;GBin1.com 最近一家设计公司发布了一个关于如何重新定义和设计维基百科的网站&#xff0c;在这里网站里详细的刨析了如何重新设计维基百科的话&#xff0c;如何做品牌设计和网站设计&#xff0c;整个设计过程都使用非常详细的文档说…

祖父元素_帮助祖父母建立Skype帐户的UX经验教训

祖父元素“Empathy is a key part of a UX designers arsenal”, they say. It’s drilled into our heads that we need to be thinking about our user, about their journey, about what works best for them. And it does feel empowering to boast of empathy, inside vis…

2022年CSS的发展如何?

大家好&#xff0c;我是若川。持续组织了8个月源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

分布式实物实现方式_这是您完成实物产品设计任务的方式

分布式实物实现方式You’ve come to the last stages of an interview. There’s only one thing left to do: the dreaded take home design assignment.您已经到达面试的最后阶段。 只剩下一件事要做&#xff1a; 可怕的带回家的设计任务。 This is the hard part of any in…