【ITニュース解説】Understanding Stacks in JavaScript
2025年09月03日に「Dev.to」が公開したITニュース「Understanding Stacks in JavaScript」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
スタックは、最後に入れたものが最初に出てくるLIFO(後入れ先出し)のデータ構造だ。pushで追加、popで削除、peekで先頭を参照する。JavaScriptでの実装例も紹介され、Undo/Redoやブラウザ履歴など、様々な場面で使われている。
ITニュース解説
プログラミングにおいてデータを効率的に管理するための基本的な構造の一つに「スタック」がある。スタックは非常にシンプルでありながら、多くの場面で活用される重要なデータ構造だ。その核心にあるのは「LIFO(Last In, First Out)」という原則である。これは「最後に入れたものが最初に出てくる」という意味で、私たちが日常で積み重ねたものを想像すると理解しやすいかもしれない。例えば、積み重ねられた本の山から本を取り出す場合、一番上に置かれた本が最も取り出しやすい。スタックも同様に、一番上(または一番奥)にある要素に対して操作を行う。
スタックの基本的な操作は主に三つある。一つ目は「プッシュ(push)」で、これはスタックに新しい要素を追加する操作だ。新しい要素は常にスタックの「上」に追加される。二つ目は「ポップ(pop)」で、これはスタックの一番上にある要素を取り除き、その要素を返す操作だ。この操作によってスタックから要素が一つ減る。三つ目は「ピーク(peek)」で、これはスタックの一番上にある要素を、削除せずに確認する操作だ。つまり、次に何が取り出されるかを知りたいが、その要素をスタックから除去したくない場合に用いる。これらの他に、スタックが現在空であるかを確認する「イズエンプティ(isEmpty)」操作や、スタックに含まれる要素の数を確認する「サイズ(size)」操作も便利だ。
JavaScriptでスタックを実装する場合、JavaScriptの配列(Array)を内部的に利用するのが一般的で、非常に効率的だ。Stackという名前のクラスを作成し、そのコンストラクタで空の配列this.itemsを初期化することで、スタックの「箱」を用意する。
各操作は次のように実装される。
push(element)メソッドは、引数として受け取ったelementをスタックに追加する。これは内部の配列this.itemsのpushメソッド(配列の末尾に要素を追加する機能)を呼び出すことで実現できる。配列の末尾がスタックの「上」に対応すると考える。
pop()メソッドは、スタックの一番上にある要素を取り除く。これは内部の配列this.itemsのpopメソッド(配列の末尾の要素を取り除き、それを返す機能)を呼び出すことで実現できる。もしスタックが空の状態でpopを呼び出すと、JavaScriptの配列のpopメソッドはundefinedを返すため、特別なエラー処理を実装しない限りundefinedが返ってくることになる。
peek()メソッドは、スタックの一番上にある要素を返す。これは内部の配列this.itemsの最後の要素を直接参照することで実現できる。JavaScriptの配列では、this.items[this.items.length - 1]と記述することで、配列の最後の要素にアクセスできる。この操作では要素は削除されないため、スタックの状態は変化しない。
isEmpty()メソッドは、スタックが空かどうかを判断する。これは内部の配列this.itemsのlengthプロパティが0であるかどうかをチェックすることで簡単に実現できる。this.items.length === 0という条件式が真であればスタックは空であり、偽であればスタックには要素が含まれていると判断できる。
size()メソッドは、スタック内の要素数を返す。これは内部の配列this.itemsのlengthプロパティの値をそのまま返すことで実現できる。
このように実装されたスタックの具体的な動作を見てみよう。まず新しいスタックのインスタンスを作成する。次に、例えば「Plate 1」をpushし、続けて「Plate 2」をpushする。この時点でスタックの一番上には「Plate 2」がある。peek()を呼び出すと「Plate 2」が返される。ここでpop()を呼び出すと、「Plate 2」がスタックから取り除かれ、その値が返される。スタックの一番上は「Plate 1」になるので、再度peek()を呼び出すと「Plate 1」が返される、という具合だ。この一連の流れは、LIFO原則がどのように機能するかを明確に示している。
スタックは、そのシンプルな構造とLIFOという明確な動作原理のため、実際のプログラミングにおいて非常に多岐にわたる場面で利用されている。
よく知られた利用例の一つに、テキストエディタの「元に戻す(Undo)」や「やり直し(Redo)」機能がある。ユーザーがテキストを編集するたびに、その操作や変更された状態がスタックにプッシュされて記録される。ユーザーが「元に戻す」を実行すると、最新の操作がスタックからポップされ、その前の状態に戻る。この機能は、直前の操作から順に巻き戻していくため、LIFOの原則が完璧に適合する。
ウェブブラウザの「戻る(Back)」や「進む(Forward)」ボタンの履歴管理もスタックの典型的な利用例だ。ユーザーが新しいページに移動するたびに、現在のページのURLがスタックにプッシュされる。「戻る」ボタンを押すと、現在のページが別の「進む」ためのスタックにプッシュされ、履歴スタックから一つ前のURLがポップされて表示される。これにより、直前に閲覧していたページへと順に戻っていくことができる。
さらに、プログラミング言語の実行環境において、関数呼び出しの管理にもスタックが用いられている。これは「コールスタック(Call Stack)」と呼ばれ、JavaScriptを含む多くの言語の実行時に不可欠な要素だ。関数が呼び出されるたびに、その関数が実行を終えたときにどこに戻るべきか、関数の引数、ローカル変数などの情報がコールスタックにプッシュされる。そして、その関数の実行が完了すると、コールスタックの一番上からその情報がポップされて取り除かれる。これにより、入れ子になった関数呼び出しが正しく処理され、呼び出し元へと正確に戻っていく仕組みが実現されている。LIFOの原則により、最も新しく呼び出された関数が最も早く実行を終え、その情報をスタックから取り除くという自然な流れが生まれる。
このようにスタックは、データの追加と削除の順序が明確に定められているため、特定の状況下で非常に強力なツールとなる。システムエンジニアを目指す初心者にとって、スタックの概念とその実装、そして実際の利用例を理解することは、プログラミングの基礎を固める上で極めて重要である。単純なデータ構造でありながら、その応用範囲の広さは計り知れない。これらの知識を深めることで、より複雑なシステムの設計やデバッグにも役立つだろう。