普通方法定义栈
使用基本的JS语法定义栈
// 定义栈function Stack() {// 因为栈是通过数值定义的this.items = [];}// 在原型上定义栈的方法Stack.prototype.push = function(elem) {this.items.push(elem);}Stack.prototype.pop = function() {return this.items.pop();}Stack.prototype.peek = function() {return this.items[this.items.length - 1];}Stack.prototype.isEmpty = function() {return this.items.length === 0 ? true : false;}Stack.prototype.clear = function() {this.items.length = 0;}Stack.prototype.size = function() {return this.items.length;}var a = new Stack();a.push(1);a.push(2);a.push(3);a.push(4);// a 可以访问到原数组a.items.push(123);console.log(a);
输出结果
出现的问题
不仅 a 可以直接使用 push , 并且能够直接访问到 items, 原本数组 ,并且可以通过原本数组的方法 push 也能实现添加
a.items.push(123);因此这种方法不严谨, 具有漏洞
能够解决问题,主要是因为 a 能够访问到 items 原数组, 并且能够使用数组原生的方法。
解决:
- 私有属性
- Symbol 定义原数组,实例化的变量是访问不到 Symbol 的成员的
使用Symbol 定义栈
// 使用 Symbol 创建var _items = Symbol(); // 访问属性 _itemsfunction Stack() {// 因为栈是通过数值定义的// this.items = [];// 使用Symbol的属性,创建数组this[_items] = []}// 在原型上定义栈的方法Stack.prototype.push = function(elem) {this[_items].push(elem);}Stack.prototype.pop = function() {return this[_items].pop();}Stack.prototype.peek = function() {return this[_items][this[_items].length - 1];}Stack.prototype.isEmpty = function() {return this[_items].length === 0 ? true : false;}Stack.prototype.clear = function() {this[_items].length = 0;}Stack.prototype.size = function() {return this[_items].length;}var a = new Stack();a.push(1);a.push(2);a.push(3);a.push(4);// console.log(a.Symbol()); // 改为Symbol后,a访问不了Symbol成员// 使用Symbol还具有漏洞// ES6 可以通过方法可以获取到Symbol的属性console.log(Object.getOwnPropertySymbols(a)); // 能够访问到Symbolvar key = Object.getOwnPropertySymbols(a)[0];console.log(key);// 拿到key 之后 就可以使用 Symbol定义的数组的push 方法a[key].push(456);console.log(a); // 能够可以添加// for (var i in a) {// console.log(i);// }
输出结果
出现的漏洞问题
ES6 可以通过方法可以获取到Symbol的属性,
Object.getOwnPropertySymbols(a)能够访问到Symbol 的成员 , 然后保存key , a可以通过key访问到 Symbol 的原数组。
使用 WeakMap定义栈
因为 WeakMap 是弱引用,这意味着在没有其他引用存在时垃圾回收能正确进行。和 WeakMap的一些特性,是用 WeakMap 更好的定义栈
// 3 使用 WeakMap 弱引用var _items = new WeakMap();function Stack() {// 因为栈是通过数值定义的// this.items = [];// 使用Symbol的属性,创建数组// this[_items] = []// 3. 创建数组. 使用 set方法 key 传入this , value传入 []_items.set(this, []);}// 在原型上定义栈的方法Stack.prototype.push = function(elem) {// 通过 get 方法 读取this, 通过 push 添加_items.get(this).push(elem);}Stack.prototype.pop = function() {return _items.get(this).pop();}// 返回栈顶元素Stack.prototype.peek = function() {return _items.get(this)[_items.get(this).length - 1];}// 判断栈是否为空Stack.prototype.isEmpty = function() {return _items.get(this).length === 0 ? true : false;}Stack.prototype.clear = function() {_items.get(this).length = 0;}Stack.prototype.size = function() {return _items.get(this).length;}var a = new Stack();a.push(1);a.push(2);a.push(3);a.push(4);a.push(5);console.log(a);console.log(a.pop());console.log(a.peek());console.log(a.isEmpty());a.clear();console.log(a.isEmpty());console.log(a.size());// 使用 栈的方法都是没有问题的
使用 以上定义的方法, 因为WeakMap 是全局变量,在调用函数是会产生闭包
对代码优化 , 使用立即执行函数 ()()
// 使用立即执行函数
var Stack = (function() {
var _items = new WeakMap();
// 定义的方法
var Stack = function() {
// 因为栈是通过数值定义的
// this.items = [];
// 使用Symbol的属性,创建数组
// this[_items] = []
// 3. 创建数组. key 传入this , value传入 []
_items.set(this, []);
}
// 在原型上定义栈的方法
Stack.prototype.push = function(elem) {
// 读取this, 通过 push 添加
_items.get(this).push(elem);
}
Stack.prototype.pop = function() {
return _items.get(this).pop();
}
// 返回栈顶元素
Stack.prototype.peek = function() {
return _items.get(this)[_items.get(this).length - 1];
}
// 判断栈是否为空
Stack.prototype.isEmpty = function() {
return _items.get(this).length === 0 ? true : false;
}
Stack.prototype.clear = function() {
_items.get(this).length = 0;
}
Stack.prototype.size = function() {
return _items.get(this).length;
}
return Stack;
})()
在进行对代码进行优化, 使用 ES6 class 类 和执行函数。
// 使用 ES6 的class类 和 立即执行函数
var Stack = (function() {
var _items = new WeakMap();
return class Stack {
constructor() {
// 定义初始化数据
_items.set(this, []);
};
// 定义方法
push(elem) {
// 读取this, 通过 push 添加
_items.get(this).push(elem);
}
pop() {
return _items.get(this).pop();
}
// 返回栈顶元素
peek() {
return _items.get(this)[_items.get(this).length - 1];
}
// 判断栈是否为空
isEmpty() {
return _items.get(this).length === 0 ? true : false;
}
clear() {
_items.get(this).length = 0;
}
size() {
return _items.get(this).length;
}
toString() {
// 获取toString 方法
return _items.get(this).toString();
}
};
})()
输出结果

