学习资料
《学习JavaScript数据结构与算法》-- 第二版
参考资料
定义
栈是一种遵循先进后出,后进先出(LIFO
)的有序集合;
栈顶
栈底
实现
通过创建一个类来表示栈,使用数组这种数据结构来存储栈中的数组,栈顶对应数组最后一位元素,栈底对应数组的第一位元素;
栈的方法:
1.push
:向栈中添加元素
调用数组的push
方法
2.pop
:删除栈中的元素
调用数组的pop
方法
3.peek
:返回栈顶元素,不对栈进行任何的修改,不会删除栈顶元素,只是返回栈顶元素
返回数组的最后一位元素;
4.isEmpty
: 判断栈是否为空,为空,则为true
,反之为false
;
判断数组的长度是否0;
5.clear
:清空栈;
6.size
:返回栈的长度
返回数组的长度
栈的实现方式ES5
/**
* @Descroption 通过创建类的方式创建栈,使用数组来保存栈中的数据
* 栈顶对应数组的最后一个元素,栈底对应数组的
* @author xl
* @createTime 2019-03-05
*/
function Stack() {
let items = [];
// 向栈添加元素
this.push = function(item) {
items.push(item);
};
// 从栈移除元素
this.pop = function() {
return items.pop();
};
// 返回栈顶元素
this.peek = function() {
return items[items.length - 1];
};
// 检查栈是否为空
this.isEmpty = function() {
if (items.length === 0) {
return true;
} else {
return false;
}
};
// 栈的长度
this.size = function() {
return items.length;
};
// 打印栈元素
this.print = function() {
console.log(items.toString());
};
// 清空栈
this.clear = function() {
items = [];
};
}
// 栈的使用
// 初始化栈
let stack = new Stack();
console.log(stack.isEmpty());
stack.push(1)
stack.push(2)
console.log(stack.peek());
console.log(stack.size());
console.log(stack.print());
stack.pop();
stack.pop();
console.log(stack.peek());
console.log(stack.size());
console.log(stack.print());
栈的实现方式ES6
class Stack {
constructor() {
this.items = [];
}
// 栈方法
push(item) {
this.items.push(item);
}
...
}
这种实现方式的优点:
1.代码简洁,美观,
2.ES6的类是介于原型的,基于原型的类比基于函数的类更节省内存
这种实现方式的缺点:
1.ES6的类是介于原型的,但不能够声明私有属性(变量)或方法
解决ES6中使用类定义栈不能声明私有属性或方法的解决方法:
1.利用ES6中限定作用域的Symbol实现类
let _items = Symbol();
class Stack {
constructor() {
this[_items] = [];
}
// 栈方法
push(item) {
this[_items].push(item);
}
pop() {
return this[_items].pop();
}
peek() {
return this[_items][this[_items].length - 1];
}
// 检查栈是否为空
isEmpty() {
if (this[_items].length === 0) {
return true;
} else {
return false;
}
};
// 栈的长度
size() {
return this[_items].length;
};
// 打印栈元素
print() {
console.log(this[_items].toString());
};
// 清空栈
clear() {
this[_items] = [];
};
}
问题:
这种方式创建的一个假的私有变量,ES6
中新增的Object.getOwnPropertySymbols()
能够获取到类中所有使用Symbol
声明的属性,并且获取到的属性可以被更改
let stack = new Stack();
stack.push(1)
let objectSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectSymbols);
stack[objectSymbols[0]].push(3)
stack.print() // 1,3
2.利用ES6的WeakMap实现类
WeakMap
可以声明私有变量,加闭包用于限定items
let Stack1 = (function() {
// 利用WeakMap 实现类
const items = new WeakMap();
class Stack1 {
constructor() {
items.set(this,[]);
}
// 栈方法
push(item) {
let s = items.get(this);
s.push(item);
}
pop() {
let s = items.get(this);
return s.pop();
}
peek() {
let s = items.get(this);
return s[s.length - 1];
}
// 检查栈是否为空
isEmpty() {
let s = items.get(this);
if (s.length === 0) {
return true;
} else {
return false;
}
};
// 栈的长度
size() {
let s = items.get(this);
return s.length;
};
// 打印栈元素
print() {
let s = items.get(this);
console.log(s.toString());
};
// 清空栈
clear() {
items.set(this,[])
};
}
return Stack1;
})();
let stack1 = new Stack1();
stack1.push(1)
stack1.push(2)
console.log(stack1.size());
console.log(stack1.print());
console.log(stack1.peek());
console.log(stack1.isEmpty());
console.log(stack1.clear());
console.log(stack1.isEmpty());
这种方式的缺点:
扩展类无法继承私有属性;
网友评论