【若川视野 x 源码共读】第32期 | yocto-queue 队列 链表

142 阅读2分钟

yocto-queue 队列

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

yocto-queue

该库使用js实现了一个简单队列

  • size获取当前队列的长度
  • dequeue() 删除头部,返回被删除的项
  • enqueue() 从队列尾部添加一项
  • 可以使用扩展运算符,将队列通过数组返回

解析

源代码

/*
How it works:
`this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.
*/

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

初始化

这里使用了es6新增的class语法,在每次创建该构造对象时,使用了clear方法,清空了#head,#tail,#size

为了防止外部修改状态,使用了私有属性,其中#为es6新增的语法糖

这里有个Node构造函数,存储next下一个指向和value当前值,用于队列中添加的数据项

新增

调用enqueue,先判断当前#head是否存在值。

  • 如果不存在,代表第一次添加,将创建的node添加给#head 和 #tail。
  • 如果存在,#tail 此时为队列尾部,将node 赋值给#tail.next,并且将node赋值给#tail,这样上一次的尾部指向这次的node 实现了尾部链接

删除

调用dequeue,优先判断#head是否存在

  • 如果不存在代表没有值可以删除,返回空。
  • 如果存在,将当前#head的next赋值给#head,返回之前的#head.value

获取长度

这里使用了一个访问器,返回了私有变量#size

扩展运算符返回数组

由于扩展运算符(...)也会调用默认的 Iterator 接口 这里实现了Symbol.iterator方法, 这里通过一个while循环,判断当前#head的value值,如果#head存在就yield 当前的value值,从而实现个Iterator

测试

该库使用ava进行测试 对其几个方法进行测试,

  • is断言来判断t.is(queue.dequeue(), '🌈');
  • deepEqual断言来测试interator接口t.deepEqual([...queue], [1,2,3]);

结束语

通过阅读yocto-queue,学习了队列的实现,ava测试的使用,扩展运算符的实现需要遍历器Iterator,es6新增的class语法的使用