whileループと関数の基礎:再利用性の概念

whileループと非同期処理の連携:イベントループの理解(VSCODE画面)
目次

whileループの構文と特徴:条件が真である限り繰り返す仕組み

ループ処理の基本概念
プログラミングで、同じコードのかたまりを何度も実行する「ループ処理」は、条件分岐と並ぶ制御フローの基本です。ソースコードでは繰り返しの代表としてforループが紹介されていますが、whileループも同じくらい重要です。forループは「初期化式・条件式・増分式」を1つにまとめて書けるため、回数が決まっている繰り返しに向いています。一方、whileループはもっとシンプルで、「条件が成り立っている間だけ処理を続ける」という形を取ります。
whileループの構文構造
whileループの書き方はとても単純で、条件式を評価し、その結果がtrue(真)の間はブロック内の処理を繰り返します。ソースコードにはwhileループを使った実装例が含まれています。
const startTime = new Date();
while (new Date() – startTime < second);
このコードは、指定した時間が経つまでループを回し続けて処理を止める「スリープ関数」の例です。whileの()の中にある条件式(現在時刻−開始時刻が指定秒数より小さいか)が繰り返しチェックされ続けます。whileループはこのように「条件だけ」を受け取り、条件がfalse(偽)になるまで、ブロック内の処理(上の例では空文)を繰り返します。
ブロッキングとメインスレッドへの影響
whileループの特徴として、条件がtrueである限りメインスレッドを占有し続ける点があります。JavaScriptは基本的にシングルスレッドで動き、同じメインスレッドでJavaScriptの実行と画面描画も行っています。ソースコードのwhileループによるスリープ処理は同期的に進むため、指定秒数の間は他の処理(クリックへの反応など)を完全に止めてしまいます。これが「ブロッキング」で、ブラウザが固まったように見える原因です。whileループを使うときは、条件の作り方やループ内の処理内容に十分注意が必要です。

whileループと無限ループの注意点:同期処理の落とし穴

無限ループのメカニズム
whileループで特に警戒すべきバグが「無限ループ」です。これは、継続条件がずっとtrueのままで、プログラムがループから抜け出せない状態を指します。forループなら増分式が構文に入っているので、カウンター更新の書き忘れが起きにくい構造です。しかしwhileループは、ブロック内で自分で状態を変えない限り、条件式の結果が変わりません。ソースの例は new Date() で時刻が更新され続けるため、いつか条件がfalseになりますが、もし条件が固定(例:while(true))だったり、変数の更新を忘れたりすると、ブラウザのタブがクラッシュする原因になります。
シングルスレッドと同期処理の制約
JavaScriptは同期処理(順番に実行する処理)が基本なので、無限ループや長いwhileループが起きると、後ろの処理が一切動かなくなります。ソースの実験例では、whileループで作ったsleep関数が動いている5秒間は、ボタンをクリックしても「clicked」が表示されず、スリープが終わってからまとめて出力される挙動が確認されています。これは、whileループがメインスレッドを占有している間、クリックイベントの処理が実行できず待たされるためです。このようにwhileループは強力ですが、シングルスレッドのJavaScriptではUXを損なうリスクもあります。長時間の計算が必要なら、Web Workerなど別スレッドを使うか、非同期処理を前提にした設計が求められます。

関数とは何か:コードの再利用性とモジュール化

関数の定義と役割
関数とは、ある作業(タスク)を行う処理をひとまとめにし、名前を付けて何度でも呼び出せるようにした「再利用できるコードのかたまり」です。同じ処理を何度も書くのは非効率で、ミスも増えます。関数を使えば、一度作ったロジックを色んな場所から呼び出せるため、重複を避けられます。これはDRY(Don’t Repeat Yourself)原則の実践でもあります。ソースコードでは、functionを使った宣言が紹介されています。
function add(a, b) {
return a + b;
}
この関数は add(3, 4) のように呼び出せば、引数を変えて何度でも使えます。
モジュール化と可読性の向上
関数化のもう一つの大きな利点は、コードが読みやすくなることです。複雑な処理の途中に細かい計算や通信のロジックがベタ書きされると、全体の流れが見えにくくなります。処理を関数に切り出し、fetchData や sleep のように意味の分かる名前を付けると、「何をする処理か」が一目で分かります。ソースコードでは、Qiita APIから取得する非同期処理をfetchQiitaItemsという関数にまとめており、メインの流れでは呼び出すだけで済む形になっています。関数はプログラムを部品(モジュール)として整理し、管理しやすくするための基本要素です。

関数の引数と戻り値の仕組み:データの入出力

引数(Parameters)によるデータの受け渡し
関数を「使い回せる形」にするには、外からデータを渡して、そのデータに応じて処理できる必要があります。その仕組みが引数です。add(a, b) の a と b は仮引数で、呼び出し時に add(3, 4) のように実際の値(実引数)を渡すと、関数の中では a=3、b=4 として計算が行われます。引数があることで、同じadd関数でも add(10, 20) や add(100, 500) のように別の値で同じロジックを使えます。
戻り値(Return Value)による結果の返却
関数の処理結果を呼び出し元へ返す仕組みが戻り値です。returnの後に書いた値や式の結果が、関数の出力になります。ソースでは return a + b; で計算結果を返し、それが変数resultに入っています。
const result = add(3, 4); // resultには7が入る
戻り値を使うと、その結果を別の計算に使ったり、別の関数の引数にしたりできます(関数の合成)。また非同期関数(async function)では、戻り値は自動でPromiseになります。ソースのsleep関数のように return new Promise(…) としてPromiseを返せば、呼び出し側で.then()やawaitを使って処理の流れを制御できます。

変数のスコープと関数の関係:グローバルとローカル

スコープの基本概念
関数を理解するうえで重要なのが「変数のスコープ(有効範囲)」です。スコープとは、その変数をどこから参照できるかを決めるルールです。JavaScriptには大きく「グローバル」と「ローカル」があります。
・グローバルスコープ:ページ全体から参照できる変数
・ローカルスコープ:関数やブロックの中だけで有効な変数
関数スコープとローカル変数
関数内で宣言した変数は、その関数の中だけで使えるローカル変数になります。これを関数スコープと呼びます。ソースの例では次のように書かれています。
function scopeUse() {
var valGlobal1 = “local”;
console.log(“in local valGlobal1 = ” + valGlobal1);
}
ここでは、関数内のvalGlobal1が外側の同名変数より優先されます。関数スコープがあることで、外の変数名と衝突する心配を減らし、意図しない上書き(競合)を防げます。多人数開発やライブラリ利用では特に重要です。
letとvarの違いとブロックスコープ
ES2015(ES6)以降、varに加えてletとconstが使われるようになりました。varは関数スコープですが、ifやforの{}にはスコープを作りません。一方、letとconstはブロックスコープを持ち、ifやfor内で宣言した変数は外から触れません。現在はlet(再代入OK)とconst(再代入NG)を使い分けるのが一般的で、スコープ管理がしやすくなりバグも減らせます。

アロー関数の構文と特徴:モダンな関数の書き方

アロー関数の基本構文
ES2015(ES6)で追加されたアロー関数は、関数を短く書くための記法です。functionの代わりに => を使います。ソースの例は次の通りです。
const greet = (name) => {
return こんにちは、${name}さん!;
};
特に、関数を引数として渡す場面(コールバック関数)で短く書けるため、現代のJavaScriptではよく使われます。
アロー関数の省略記法
アロー関数には省略のルールがあります。

引数が1つなら()を省略できる(例:name => { … })
処理が1行で、そのまま返すだけなら{}とreturnを省略できる(暗黙のreturn)
ソースの例では、valを受け取り sleep(val) の結果をそのまま返す形として簡潔に書かれています。
thisの扱いの違い
ソース内で詳しく触れられていませんが、重要な違いとしてthisの扱いがあります。従来のfunctionは呼び出し方でthisが変わりますが、アロー関数は定義した場所のthisを引き継ぎます。クラスやオブジェクト内で使うときに影響するポイントです。

whileループと非同期処理の連携:イベントループの理解

同期的なwhileループの問題点
1章でも触れた通り、whileループで時間を待つ(スリープする)方法はメインスレッドを止めてしまいます。ソースのsleep関数は指定時間が過ぎるまでCPUを回し続けるため、その間ブラウザは描画更新もイベント処理もできません。これは同期処理として動くからです。
非同期処理による解決
JavaScriptでは、時間がかかる処理(タイマーや通信など)は非同期処理で扱うのが基本です。非同期の場合、処理はいったんメインスレッドから離れ、Web API(ブラウザの機能)側で実行されます。たとえばsetTimeoutなら、待っている間もメインスレッドは空くので、クリックなど他の処理が動けます。ソースの例では、setTimeoutを使うことでログの順序が 1 -> 3 -> 2 となり、待機中でも後ろのコードが先に動くことが確認できます。
イベントループとタスクキュー
非同期処理の裏にはイベントループがあります。
コールスタック:今実行中の関数が積まれる場所
Web API:setTimeoutやfetchなどの処理が動く場所
タスクキュー:終わった非同期処理のコールバックが並ぶ場所

イベントループ:コールスタックが空いたらタスクキューから取り出して実行する仕組み
whileのような長い同期処理はコールスタックを占有し続けるため、イベントループが回れず画面がフリーズします。一方、Promiseやasync/awaitを使えば、待ちながらもメインスレッドを止めない設計にできます。

DOM操作とイベント処理における関数:ユーザー操作への反応

DOM要素の取得と操作
JavaScriptの大きな役割の一つは、Webページの見た目や構造(DOM)を動的に変えることです。ソースでは document.getElementById や querySelector で要素を取得し、textContent を書き換える方法が解説されています。DOMを操作する処理は、関数としてまとめることが多く、「ボタンが押されたらリストを追加する」のような動作を部品化できます。
イベントリスナーとコールバック関数
ユーザー操作に反応するには addEventListener を使います。
button.addEventListener(“click”, () => {
console.log(“ボタンがクリックされました!”);
});
ここで第2引数に渡しているアロー関数が「コールバック関数」です。クリックが起きたタイミングでブラウザがこの関数を呼び出します。イベント処理を関数にすると、「起きたら何をするか」を分離でき、コードの構造が整理されます。さらにthisやイベントオブジェクトを使って、クリックされた要素やイベントの情報にアクセスできます。

コールバック関数と高階関数:関数の再利用性を高める

コールバック関数の概念
コールバック関数とは、「他の関数に引数として渡され、処理の途中や終わりで呼び出される関数」のことです。イベントリスナー、setTimeout、配列のforEachなどで頻繁に登場します。ソースのfetchDataの例を見てみましょう。
function fetchData(callback) {
setTimeout(() => {
const data = “データ”;
callback(data);
}, 1000);
}
このfetchDataは、データ取得後に何をするかをcallbackとして受け取ります。fetchData自身は「データを取る」ことに集中し、「表示する」「保存する」といった使い方は呼び出し側が決められるため、再利用しやすい構造になります。
高階関数による抽象化
関数を引数に取ったり、戻り値として関数を返したりする関数を高階関数と呼びます。ソースのmakeOnLoadCallbackは、関数を戻り値として返す例です。
function makeOnLoadCallback(name) {
return function() { … };
}
このように関数を作ったり返したりできると、共通ロジックをテンプレート化して、状況に応じて違う動きをする関数を動的に作れます。再利用性を極限まで高めるための高度な考え方です。

クラスとオブジェクト指向における関数(メソッド):データと処理のセット

オブジェクト指向とメソッド
JavaScriptはオブジェクト指向(OOP)をサポートします。オブジェクト指向では、データ(プロパティ)とその操作(メソッド)を1つのまとまりとして扱います。オブジェクトの中に入っている関数をメソッドと呼びます。ソースの例は次の通りです。
const person = {
name: “太郎”,
// 以下はメソッドのイメージ(ソースコード70より補足)
getName: function() {
return this.name;
}
};
メソッドの中では this を使うことで、そのオブジェクト自身のデータ(nameなど)にアクセスできます。
クラスとコンストラクタ
ES2015でclass構文が追加されましたが、本質はプロトタイプベースの継承です。ソースでは古い書き方として、関数でクラスのような役割を作る方法が紹介されています。これはコンストラクタ関数と呼ばれます。
var Student = function(name, id) {
this.name = name;
this.id = id;
this.getName = function() {
return this.name;
};
};
このように関数(コンストラクタ)で「ひな型」を用意すると、new Student(…)で同じ構造と機能を持つオブジェクト(インスタンス)を何個でも作れます。これは再利用性という観点で、関数が果たす大きな役割の一つです。データの形と操作ロジックをセットにして、使い回せる部品として扱えるようになります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次