github主页:https://github.com/A15162252289
什么是栈?
栈是一种遵从后进先出(LIFO)原则的有序集合。新添加的或待删除的元素都保存在栈的同一端,称之为栈顶,另一端则为栈底。在栈里,新元素靠近栈顶,旧元素靠近栈底。
如何实现栈?
1.首先声明一个类,并初始化一个数组用来保存栈里的元素:
function Stack (){
let items=[];
}
2.为栈声明一些方法:
push():向栈中添加元素到栈顶
pop():移除栈顶的元素并返回被移除的元素
peek():仅返回栈顶的元素不做其他任何操作
isEmpty():判断栈中是否存在元素
clear():清空栈
size():返回栈中元素的个数
以下为代码实现:
this.push = function (element) {
items.push(element);
}
this.pop = function () {
return items.pop();//返回栈顶的元素
}
this.peek = function () {
return items[items.length-1];
}
this.isEmpty = function () {
return items.length == 0;
}
this.size = function () {
return items.length;
}
this.clear = function () {
items = [];
}
3.使用ES6语法声明Stack类
class Stack {
constructor () {
this.items=[];
}
push(element) {
this.items.push(element);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[items.length-1];
}
isEmpty() {
return this.items.length == 0;
}
size() {
return this.items.length;
}
clear() {
this.items = [];
}
}
4.ES6类的缺陷
我们知道,在ES6中的类只是个语法糖,只是写着方便。实际上类还是基于原型的。虽然基于原型的类比基于函数的类更省内存,也更适合创建多个实例,但不能声明私有属性或方法。之前我们创建的Stack类中items数组是公用的,这是极其危险的行为。
有两种解决办法
- 使用ES6限定作用域Symbol实现类(假的私有变量)
let _items=Symbol();
class Stack {
constructor () {
this[_items] = [];
}
//其他方法中把之前的this.items全部替换为this[_items]
}
然而在ES6中还是可以通过Object.getOwnPropertySymbols取得类中声明的所有Symbols属性:
let stack = new Stack();
let objectSymbols = Objcet.getOwnPropertySymbols(stack);
stack[objectSymbols[0]].shift();//可以进行任意的数组操作!
由此我们可以看出并没有创造一个真正的私有变量
- 使用ES6的WeakMap实现类
const items = new WeakMap();//创建WeakMap实例
class Stack {
constructor () {
items.set(this,[]);//设置键值
}
push (element) {
let s = items.get(this);//根据键取得值
s.push(element);
}
//其他方法
}
不难发现items是个全局变量,因此我们还需要个闭包(外层函数)把Stack类包起来:
let Stack = (function () {
const items = new WeakMap();//创建WeakMap实例
class Stack {
constructor () {
items.set(this,[]);//设置键值
}
push (element) {
let s = items.get(this);//根据键取得值
s.push(element);
}
//其他方法
return Stack;
})()
这种方法创造了一个完全私有的变量,使得扩展类也无法继承这个私有属性。
总结:javascript是基于原型的,没有最好的办法为类创建私有变量和方法,使用哪种方法取决于要处理的数据量,要创造的实例个数,以及其他约束条件。最终还是取决于你。(方法待补充)
Github源码链接:link.