普通方法定义栈
使用基本的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(); // 访问属性 _items
function 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)); // 能够访问到Symbol
var 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();
}
};
})()
输出结果