🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[success] # 实现一个js的栈 ~~~ 1.上个章节我们说了一个实现思路是通过'数组形式'来实现一个栈,这种栈叫做'顺序栈', 这个章节就用js 实现一个顺序栈 ~~~ >[info] ## 实现是一个顺序栈 -- 先进后出(LIFO 原则) ~~~ 1.首先'顺序栈' 是基于数组,只能对栈顶进行操作因此接下来要实现的顺序栈会有以下的方法 push(element(s)):添加一个(或几个)新元素到栈顶。 pop():移除栈顶的元素,同时返回被移除的元素。 peek():返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它)。 isEmpty():如果栈里没有任何元素就返回 true,否则返回 false。 clear():移除栈里的所有元素。 size():返回栈里的元素个数。该方法和数组的 length 属性很类似。 ~~~ * 栈顶如图 ![](https://img.kancloud.cn/19/01/1901c976e71669b1ae335a5554114f5d_129x164.png) >[danger] ##### 代码实现 ~~~ class StackArray{ constructor(){ // 创建一个数组用来保存栈 this.item = [] } // 栈顶添加 push(element){ this.item.push(element) } // 移除栈顶元素 pop(){ return this.item.pop() } // 返回当前栈顶元素 peek(){ return this.item[this.item.length-1] } // 判断当前栈是否有元素 isEmpty(){ return this.item.length === 0 } // 移除栈里所有元素 clear(){ this.item = [] } // 返回栈中的个数 size(){ return this.item.length } toArray() { return this.items; } toString() { return this.items.toString(); } } ~~~ >[info] ## 使用js 对象为基础实现 -- 栈 ~~~ 1.数组是连续的开辟内存空间所以对空间的占用相对较多,减少较少的 空间使用可以考虑对象这种创建方式 ~~~ >[danger] ##### 代码实现 ~~~ class Stack{ constructor(){ this.count = 0 this.items = {} } // 检查栈是否为空 isEmpty(){ return this.count === 0 } // 添加元素 push(element){ this.items[this.count ++ ] = element } // 删除元素 pop(){ // 如果栈为空删除返回undefined if(this.isEmpty()){ return undefined } const result = this.items[--this.count ] delete this.items[this.count] return result } // 返回栈顶元素 peek() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } // 栈的大小 size(){ return this.count } // 清楚栈 clear() { // 循环这种 利用先进后出按顺序依次删除 /* while (!this.isEmpty()) { this.pop(); } */ // 这种最简单粗暴一步到位 this.items = {}; this.count = 0; } toString() { if (this.isEmpty()) { return ''; } // 为了可以拼接处1,2,3 let objString = `${this.items[0]}`; for (let i = 1; i < this.count; i++) { objString = `${objString},${this.items[i]}`; } return objString; } } const stack = new Stack() stack.push(1) stack.push(2) stack.push(3) console.log(stack.toString()) // 1,2,3 ~~~ >[info] ## 上面的两种实现的弊端 ~~~ 1.上面的两种已经实现了,但是不是那么友好,因为对外暴露了items, 这样使用的人可以任意对暴露的items 进行更改es10是具备私有属性, 我们可以将这些不想对外暴露的属性设置为私有属性 2.当然我们也可用'symbol'来操作,但这依旧会有问题 ~~~ >[danger] ##### 使用symbol 创建私有属性 ~~~ const _items = Symbol('stackItems'); class Stack { constructor () { this[_items] = []; } // 栈的方法 } // 但是依旧可以使用 getOwnPropertySymbols 获取symbol 并且更改 const stack = new Stack(); stack.push(5); stack.push(8); let objectSymbols = Object.getOwnPropertySymbols(stack); console.log(objectSymbols.length); // 输出 1 console.log(objectSymbols); // [Symbol()] console.log(objectSymbols[0]); // Symbol() stack[objectSymbols[0]].push(1); stack.print(); // 输出 5, 8, 1 ~~~ >[danger] ##### 使用 WeakMap * WeakMap配合 数组 ~~~ 1.采用这种方法,代码的可读性不强,而且在扩展该类时无法继承私有属性 ~~~ ~~~ const items = new WeakMap(); class Stack { constructor () { items.set(this, []); } push(element){ const s = items.get(this); s.push(element); } pop(){ const s = items.get(this); const r = s.pop(); return r; } // 其他方法 } ~~~ * WeakMap配合 对象 ~~~ const _items = new WeakMap(); const _count = new WeakMap(); class Stack { constructor() { _count.set(this, 0); _items.set(this, {}); } push(element) { const items = _items.get(this); const count = _count.get(this); items[count] = element; _count.set(this, count + 1); } pop() { if (this.isEmpty()) { return undefined; } const items = _items.get(this); let count = _count.get(this); count--; _count.set(this, count); const result = items[count]; delete items[count]; return result; } peek() { if (this.isEmpty()) { return undefined; } const items = _items.get(this); const count = _count.get(this); return items[count - 1]; } isEmpty() { return _count.get(this) === 0; } size() { return _count.get(this); } clear() { /* while (!this.isEmpty()) { this.pop(); } */ _count.set(this, 0); _items.set(this, {}); } toString() { if (this.isEmpty()) { return ''; } const items = _items.get(this); const count = _count.get(this); let objString = `${items[0]}`; for (let i = 1; i < count; i++) { objString = `${objString},${items[i]}`; } return objString; } } ~~~ >[info] ## 总结 ~~~ 1.当然了可以使用es10 私有属性或者使用ts,毕竟每个语言都有自己的 特点 ~~~