Stack via Array
JavaScript does not ship a dedicated `Stack` class because `Array` already supports O(1) `push` and `pop`. This snippet covers the array-as-stack idiom, a tiny class wrapper for self-documenting code, and a balanced-parentheses checker that demonstrates the canonical stack-driven algorithm. Use this template anywhere the LIFO order matters: undo, expression evaluation, DFS bookkeeping.
402 views
8
const stack = [];
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.length); // 3
console.log(stack[stack.length - 1]); // 3 (peek)
console.log(stack.pop()); // 3
console.log(stack); // [1, 2]Array.prototype.push and Array.prototype.pop operate on the end of the array, both in O(1) amortized time. Reading the last element via array[array.length - 1] (or array.at(-1)) gives a non-mutating peek. This pattern is what most JavaScript code uses in place of a dedicated stack class. The trade-off versus a real Stack is that the array exposes other methods (shift, splice, indexed access) which a strict consumer might mis-use; if discipline matters, wrap it in a class.
class Stack {
#data = [];
push(item) { this.#data.push(item); return this; }
pop() { return this.#data.pop(); }
peek() { return this.#data[this.#data.length - 1]; }
get size() { return this.#data.length; }
get isEmpty() { return this.#data.length === 0; }
}
const s = new Stack();
s.push('a').push('b').push('c');
console.log(s.size); // 3
console.log(s.peek()); // c
console.log(s.pop()); // c
console.log(s.isEmpty); // falseThe class wrapper exposes only the four operations that make sense for a stack (push, pop, peek, size), which prevents downstream code from accidentally calling shift or splicing in the middle. The private field (#data) keeps the underlying array hidden so refactoring to a different storage (e.g. a linked list for very large stacks) does not break callers. The push method returns this so calls can be chained. Reach for the class form when you want self-documenting code or when the team mixes seasoned and junior engineers.
function isBalanced(s) {
const pairs = { ')': '(', ']': '[', '}': '{' };
const stack = [];
for (const ch of s) {
if (ch === '(' || ch === '[' || ch === '{') {
stack.push(ch);
} else if (ch in pairs) {
if (stack.pop() !== pairs[ch]) return false;
}
}
return stack.length === 0;
}
console.log(isBalanced('([]{})')); // true
console.log(isBalanced('([)]')); // false (interleaved)
console.log(isBalanced('({[}]')); // false
console.log(isBalanced('')); // trueStacks shine on bracket matching because LIFO is exactly what nested structures require: every closer must match the most recent opener. The implementation pushes openers and pops on closers, comparing each pop against the expected matching pair. Returning stack.length === 0 at the end catches unclosed openers (((), and the early return false catches mismatches and excess closers. This algorithm generalises to HTML tag matching, expression parsing, and validating JSON structure.
