Finally happy to see that now we can have iterators and generators. I also need to try to have private properties too so that we have well encapsulated data structures and I see that there are Proxies and Symbols which could help me do that.
Utils:
export const isDefAndNotNull = object =>
object !== undefined && object !== null;
export const isIterable = object =>
isDefAndNotNull(object) && typeof object[Symbol.iterator] === 'function';
Code:
import {isDefAndNotNull, isIterable} from "./Utils";
function *reverseArrayGenerator(arr) {
let i = arr.length;
while(--i >= 0) {
yield arr[i];
}
}
const data = Symbol("data");
export default class {
constructor(iterable) {
this[data] = [];
if (isIterable(iterable)) {
for (let item of iterable) {
this.push(item);
}
}
}
peek() {
return this[data].slice(-1)[0];
}
push(item) {
this[data].push(item);
}
pop() {
return this[data].pop();
}
isEmpty() {
return this[data].length === 0;
}
size() {
return this[data].length;
}
toString() {
let res = [];
for (let item of this) {
res.push(item);
}
return JSON.stringify(res.join(' '));
}
[Symbol.iterator]() {
return reverseArrayGenerator(this[data]);
}
}
Test:
import {strictEqual as equal} from "assert";
import Stack from "../src/Stack";
suite("Stack", () => {
test("without iterator", () => {
const s = new Stack();
s.push(1);
equal(s.size(), 1);
equal(s.pop(), 1);
equal(s.size(), 0);
});
test("with iterator", () => {
let s = new Stack([1, 2, 3]);
equal(s.size(), 3);
s = new Stack('hello');
equal(s.size(), 5);
s = new Stack([{name: 'Foo'}, {name: 'Bar'}]);
equal(s.size(), 2);
});
test("peek", () => {
let s = new Stack([1, 2, 3]);
equal(s.peek(), 3);
s.pop();
equal(s.peek(), 2);
});
test("iterator", () => {
const s = new Stack([1, 2, 3]);
let i = 3;
for(let item of s) {
equal(item, i);
i--;
}
});
});
Reference: http://algs4.cs.princeton.edu/13stacks/Stack.java.html