1、基于函数,ES5写法
//ES5写法
//基于函数的类
function Stack() {
let items = [];
//向栈添加元素
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 = [];
};
//打印栈元素
this.print = function(){
console.log(items.toString());
};
this.toString = function(){
return items.toString();
};
}
这种基于函数的类,每次实例化都会重新定义方法,浪费内存
2、基于原型,ES6写法
//ES6写法
//基于原型
class Stack {
constructor () {
this.items = [];
}
push(element) {
this.item.push(element);
}
...
}
相当于ES5基于原型的类:
function Stack () {
this.items = []
}
Stack.prototype = {
//向栈添加元素
push: function (element) {
this.items.push(element)
},
...
}
基于原型的类虽然更省内存,也更适合创建多个实例,却不能声明私有属性(变量)或方法。
可以用ES6的限定作用域Symbol实现类
Symbol
let _items = Symbol();
class Stack2 {
constructor () {
this[_items] = [];
}
push(element){
this[_items].push(element);
}
pop(){
return this[_items].pop();
}
peek(){
return this[_items][this[_items].length-1];
}
isEmpty(){
return this[_items].length == 0;
}
size(){
return this[_items].length;
}
clear(){
this[_items] = [];
}
print(){
console.log(this.toString());
}
toString(){
return this[_items].toString();
}
}
这种方法创建了一个假的私有属性,因为ES6新增的Object.getOwnPropertySymbols方法能够获取到类里面声明的所有Symbol属性名,下面是一个破坏stack类的例子:
let 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
3、用ES6的weekMap和闭包实现
WeekMap可以确保属性是私有的
let Stack3 = (function () {
const items = new WeakMap();
class Stack3 {
constructor () {
items.set(this, []);
}
push(element){
let s = items.get(this);
s.push(element);
}
pop(){
let s = items.get(this);
let r = s.pop();
return r;
}
peek(){
let s = items.get(this);
return s[s.length-1];
}
isEmpty(){
return items.get(this).length == 0;
}
size(){
let s = items.get(this);
return s.length;
}
clear(){
items.set(this, []);
}
print(){
console.log(this.toString());
}
toString(){
return items.get(this).toString();
}
}
return Stack3;
})();
缺点:用这种方法的话,扩展类无法继承私有属性。
应用
十进制转二进制
//十进制转二进制
function divideBy2(decNumber) {
var remStack = new Stack(),
rem,
binaryString = '';
while(decNumber > 0) {
rem = Math.floor(decNumber % 2);
remStack.push(rem);
decNumber = Math.floor(decNumber / 2);
}
while(!remStack.isEmpty()) {
binaryString += remStack.pop().toString();
}
return binaryString;
}
十进制转任何进制
//十进制转任何进制
function baseConverter(decNumber, base) {
var remStack = new Stack(),
rem,
baseString = '',
digits = '0123456789ABCDEF';
while(decNumber > 0) {
rem = Math.floor(decNumber % base);
remStack.push(rem);
decNumber = Math.floor(decNumber / base);
}
while(!remStack.isEmpty()) {
baseString += digits[remStack.pop()];
}
return baseString;
}
平衡括号问题
function parenthesesChecker(symbols){
let stack = new Stack(),
balanced = true,
index = 0,
symbol, top,
opens = "([{",
closers = ")]}";
while (index < symbols.length && balanced){
symbol = symbols.charAt(index);
if (opens.indexOf(symbol) >= 0){
stack.push(symbol);
console.log(`open symbol - stacking ${symbol}`);
} else {
console.log(`close symbol ${symbol}`);
if (stack.isEmpty()){
balanced = false;
console.log('Stack is empty, no more symbols to pop and compare');
} else {
top = stack.pop();
//if (!matches(top, symbol)){
if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
balanced = false;
console.log(`poping symbol ${top} - is not a match compared to ${symbol}`);
} else {
console.log(`poping symbol ${top} - is is a match compared to ${symbol}`);
}
}
}
index++;
}
if (balanced && stack.isEmpty()){
return true;
}
return false;
}
console.log(parenthesesChecker('{([])}')); //true
console.log(parenthesesChecker('{{([][])}()}')); //true
console.log(parenthesesChecker('[{()]')); //false
汉诺塔问题
function towerOfHanoi(n, from, to, helper){
if (n > 0){
towerOfHanoi(n-1, from, helper, to);
to.push(from.pop());
console.log('-----');
console.log('Source: ' + from.toString());
console.log('Dest: ' + to.toString());
console.log('Helper: ' + helper.toString());
towerOfHanoi(n-1, helper, to, from);
}
}
var source = new Stack();
source.push(3);
source.push(2);
source.push(1);
var dest = new Stack();
var helper = new Stack();
towerOfHanoi(source.size(), source, dest, helper);
source.print();
helper.print();
dest.print();