プログラミングには、順次・分岐・反復という3つの基本的な制御構文があります。
初学者の方がこれらを使いこなせるようになれば、実装できるプログラムの幅が大きく広がります。
様々なアルゴリズムを習得して、より本格的なプログラムを組めるようになりましょう!

JavaScriptのスキルを身につけてWebエンジニアとして活躍したいなら、約15.5万の講座の中から自分に合ったものを探せるこちらのサービスがおすすめです。
習得したいスキルに合わせてプロのエンジニアが解説する動画で効率的な学習ができます!
フロントエンドエンジニアになりたい人の Webプログラミング入門

制御構造とアルゴリズム

プログラムでは、データに対して様々な処理を行います。
複雑な処理を行う際には、プログラムを構造化した制御構造を利用します。

制御構造には大きく、順次・分岐・反復に分けられます。
このような制御構造を組み合わせた、何かしらの結果を得るための手順のことをアルゴリズムといいます。
良いアルゴリズムを使えば処理も早くなり、効率の良いプログラムになります。

構造化の基本であるブロックは、プログラムを{}で囲むことでグループ化したもののことです。
制御構文でも対象となる処理をブロック化しています。

また、プログラム中で使われる変数には寿命(有効範囲)があり、これをスコープといいます。
その変数がブロック内で有効なのか、それともプログラム全体で有効なのか、ということです。
スコープの外からデータを取得したり変更したりすることはできません。

プログラムのどこからでも参照できるデータはグローバルスコープといいます。
一方で限られた範囲内でのみ扱われるデータはローカルスコープといいます。

スコープが広くなればなるほどデータが変更される可能性のある領域が増え、予期せぬエラーにつながります。
そうなると保守性・メンテナンス性が損なわれ、質の悪いコードになってしまいます。
ということでプログラムを実装する際は、グローバルスコープに依存しすぎずなるべくローカルスコープのデータを扱うようにするのが理想的です。

とはいっても最初はなかなか意識するのも難しいかと思いますので、少しずつ慣れていきましょう!

順次

ひとつ目に紹介する制御構造の順次はその名の通り、上から順番にコードを実行していくことです。
詳しく説明しなくても直感的にわかるかと思いますが、最も基本的で重要な制御構造となります。

以下のコードを実行すると、最初の方から順番にコンソールに出力されるxの値が変化していくのがわかります。

let x = 20;
console.log(x);

x = 10;
console.log(x);

x += 2;
console.log(x);

分岐

分岐条件に応じて処理を変化させるための制御構造です。
条件分岐の実現にはif文とswitch文、一行で分岐を表現できる三項演算子があります。

条件分岐というからには真偽値を持つ条件式が必要になります。
条件式には真偽値を返すような関数や、関係演算と論理演算の組み合わせを用います。

if文

条件分岐の最も基本的な実装方法はif文で、構文は以下のようになっています。

if( 条件式 )
{
    // 条件式が成り立つときに実行するプログラム
}

条件式の成否に応じて分岐される処理はブロック化しておきます。
こうしないと、どこまでがif文の中身でどこまでがelse文の中身なのか、ということがコンピュータに伝えられないからです。
ただし、処理が1行の場合にはブロック化を省略することもできます。

if文の直後に条件式を記述し、その条件式を満たしていたらその直後のブロック化された処理の中身を実行します。

以下のプログラムでは、ブラウザに確認用のポップアップを表示し、OKが押されればさらにアラートを表示するというものです。

if( confirm('Click "OK" if you agree to the terms of use.') )
{
    alert('Thank you.');
}

条件を満たさない場合の処理

条件式が成り立った場合だけではなく、成り立たなかった場合の処理を指定したいなら、if文の後ろにelse文を記述します。
構文としては以下のようになります。

if( 条件式 )
{
    // 条件式が成り立つときに実行するプログラム
}
else
{
    // 条件式が成り立たないときに実行するプログラム
}

条件式がtrueであればifの直後のプログラムを実行し、条件式がfalseであればelseの直後のプログラムを実行します。
正確には、false以外にも0や空文字(“”)、null、undefinedなどのfalsyな値であればelseの中身を、truthy(falsyではない)な値であればifの中身を実行します

以下のプログラムでは、ユーザに対してプロンプトで年齢を入力させて、その結果に応じたメッセージをコンソールに出力します。

// プロンプトに入力された値を数値型に変換して変数に代入
let num = parseInt(prompt('Please enter your age.'));

if( num >= 20 )
{
    alert('You are an adult.');
}
else
{
    alert('You are not an adult.');
}

複数条件による分岐

複数条件を用いた分岐を実装したい場合には、if文とelse if文を用います。

if文の条件を満たさなかった場合、次のelse if文でさらに条件をチェックします。
その条件を満たしていればそのブロックの処理を、満たしていなければさらにその次のelse if文の条件をチェックする、といった具合に複数の条件による分岐を行うことができます。
どの条件も満たさない場合は最後のelse文の中身の処理を実行します。

以下のプログラムではユーザにお気に入りの月(1月、2月、…)を入力させ、その月の季節を表示します。

let fav_month = parseInt(prompt('Please enter your favorite month.'));
let season = '';

if( 3 <= fav_month && fav_month<= 5 )
{
    season = 'spring';
}
else if( 6 <= fav_month && fav_month <= 8 )
{
    season = 'summer';
}
else if( 9 <= fav_month && fav_month <= 11 )
{
    season = 'autumn';
}
else if( fav_month === 12 || fav_month <= 2 )
{
    season = 'winter';
}
else
{
    alert('Please enter a number that your favorite month.');
    season = '[error]';
}

alert('Your favorite season is ' + season + '.');

switch文

switch文複数の場合分けができる条件に特化した分岐方法です。
条件式とcase文の値を逐次比較していき、一致した場合には処理を実行します。
どの条件にも一致しなかった場合には、default文の処理を実行します。

プログラム中の条件分岐には基本的にif文を用い、if文だけでどんな分岐でも表現することができます。
しかし、場合によってはswitch文を用いることによって可読性が向上することがありますので、覚えておいて損はないでしょう。

switch文の構文は以下の通りです。

switch( 条件式 )
{
    case 値1:
        // 条件式が値1に一致する場合の処理
        break;

    case 値2:
        // 条件式が値2に一致する場合の処理
        break;

    case 値3:
        // 条件式が値3に一致する場合の処理
        break;

    ...

    default:
        // 条件式がどの値にも一致しない場合の処理
}

case文の最後にはbreak文を書く場合がほとんどで、これがないと次のcaseについても検証されてしまいます(つまりすべての場合においてdefaultが実行されます。
break文は処理ブロックを抜け出す文です。

また、break文を省略した書き方をフォールスルーといい意図的に利用することも稀にあります。

以下のプログラムでは、ユーザが入力した数値をもとに条件分岐を行い表示内容を変化させます。

let fav_city = parseInt(prompt('Please enter your favorite City.\n' +
                               '1: Tokyo, 2: Osaka, 3: Nagoya'));
let city_name = '';

switch( fav_city )
{
    case 1:
        city_name = 'Tokyo';
        break;

    case 2:
        city_name = 'Osaka';
        break;

    case 3:
        city_name = 'Nagoya';
        break;

    default:
        alert('Please choose from the specified numbers');
        city_name = '[error]';
}

alert('You love ' + city_name + '!');

三項演算子

三項演算子の特徴は、条件に応じて返す値を変化させることです。
クエスチョンマーク(?)の左側にある条件式がtrueの時はコロン(:)の左側の値を、条件式がfalseの時は右側の値を返します。

let x = 条件式 ? 条件が成り立つときの値 : 条件が成り立たないときの値;

if文を用いても同様の動作をさせることはできるものの、三項演算子を用いることでよりコンパクトにコードをまとめることができます

以下のプログラムでは、ユーザがメンバーであればprice変数に300を、メンバーでなければprice変数に500を代入します。

let price = prompt('Are you a member?') === 'yes' ? 300 : 500;

alert('Price: ' + price);

本気でWebエンジニアを目指すなら、現役で活躍する講師の現場で使える技術を学べるこちらの講座がおすすめです。
コミュニティマネージャーとの面談から理想のキャリアと現状に合わせた、自分専用のコースを組み立てることができます。
まずは無料のWeb説明会に参加してみましょう!
ゼロから人気のWebスキルを学ぶなら【Cucua】

反復

反復処理を繰り返し実行する場合に用いる制御構文で、ループ処理とも言います。
反復においては、ループを継続するか打ち切るかの条件分岐を使用する必要があります。
そのため、条件分岐や条件式をしっかり理解しておかなければ少し戸惑う部分が出てくるかもしれません。

復習になりますが、条件式には真偽値を返すような関数や関係演算と論理演算の組み合わせを用います。
条件式がtrueを返すのかfalseを返すのかによって処理を分岐させます。

for文

for文は最もよく利用される繰り返し構文となっています。
以下のような構文を用いますが、処理の流れがわかりにくいのでしっかりと理解しておくことをおすすめします。

for( 初期化処理 ; 条件式 ; 更新処理 )
{
    // 繰り返し実行される処理
}

初期化処理はループの一回目のみ実行され、反復の回数をカウントするためのカウンタ変数を初期化するために用いられます。
条件式はループを継続するための条件で、カウンタ変数が条件を満たす間はfor文の中身を繰り返し実行します。
更新処理は、ループの後に毎回実行され、カウンタ変数を更新する処理を記述します。

例えば、以下のコードではfor文の中身を10回実行することになります(処理の様子がわかるようにカウンタ変数をコンソールに出力しています)。

for( let i = 0; i < 10; i++ )
{
    console.log(i);
}

最初にカウンタ変数を0にしておいて、条件式にカウンタ変数がループしたい回数未満という条件を指定するのがわかりやすいです。
はじめのうちは以下の形をテンプレートとして覚えておけば十分でしょう。

for( let i = 0; i < 繰り返したい回数; i++ )
{
    // 繰り返し実行される処理
}

for-of文

for-of文は、配列の要素に対する繰り返し処理を記述するのに非常に適した構文です。
for文のようにループの回数を指定するのではなく、配列の要素数分だけ処理を繰り返します

for( 配列から取り出した値を受け取る変数名 of 配列 )
{
    // 繰り返し実行される処理
}

この構文では、配列の要素を順番に取り出してループ内で使用することができます。
ofの左側で定義された変数は、for-of文の中でのみ有効なローカル変数となっています。

let fruits = ['apple', 'banana', 'melon'];

for( const fruit of fruits )
{
    console.log(fruit);
}

また、オブジェクト(連想配列)の配列においてプロパティ名(キー値)を指定してfor-of文を使用することも可能です。

let members = [
        {
            "ID": 1,
            "name": "Sato",
            "age": 30
        },
        {
            "ID": 2,
            "name": "Yamada",
            "age": 25
        },
        {
            "ID": 3,
            "name": "Kimura",
            "age": 50
        }
];

for ( const {name} of members )
{
    console.log(name);
}

for-in文

for-of文では配列の各要素を取り出しながら繰り返し処理を行うことができました。
for-in文ではオブジェクト(連想配列)の各要素に対して繰り返し処理を実行できます

for( オブジェクトから取り出したプロパティを受け取る変数名 in オブジェクト )
{
    // 繰り返し実行される処理
}

for-in文で取り出すのは値ではなくプロパティ名(キー値)となっていることには注意が必要です。

item =
{
    name: "item",
    price: 100,
    stock: 20
}

for ( const key in item )
{
    console.log(key);

    console.log(item[key]);    // 値を取り出したい場合
}

while文

while文はfor文をより単純化したような構文になっており、条件式を満たしている間は処理を繰り返し続けます

while( 条件式 )
{
    // 繰り返し実行される処理
}

繰り返し処理を行いたい場合のほとんどがカウント変数を用いるので、条件式のほかに初期化処理や更新処理を記述する必要があります。
こういったときにはfor文の方が便利です。

一方で、繰り返す回数が決まっていない場合など状況ではwhile文を使うのが便利です。

以下のプログラムは、1~10までのランダムに生成された数値を予想して5回以内に正解する、というゲームです。
cntというカウント変数を使用して、while文で最大5回繰り返し処理を行っています。
しかし、プロンプトに入力した数値がランダムに生成された数に一致していればすぐにループを抜け出します。

// 1~10までのランダムな整数を生成
const ans = Math.floor(Math.random() * 10) + 1;
// カウント変数の初期化処理
let cnt = 1;

while ( cnt <= 5 )
{
    // プロンプトに入力した値が答えと一致していれば処理を行う
    if ( parseInt(prompt(cnt + ': Please enter a number.')) === ans )
    {
        alert('Is the correct answer!');
        break;
    }

    // カウント変数の更新処理
    cnt++;
}

alert('Answer: ' + ans);

while文を使うときには、以下の例のように無限ループが発生しないように注意してください。
無限ループが発生すると、プログラムがそれより先に進めなくなります。

while( true )
{
    console.log('Hello, World!');
}

do-while文

do-while文の考え方は基本的にはwhile文と同じです。

do
{
    // 繰り返し実行される処理
} while( 条件式 );

while文との違いは、条件式が処理を繰り返すブロックの後方に書かれていることです。
while文では条件を判定してから処理を実行していますが、do while文では処理を実行してから条件の判定を行います。
これは、条件を満たすか満たさないかといったことに関わらず、必ず1回は処理を実行したいというときに使用します。

以下は先ほどと同様の数当てゲームのプログラムです。
ただし、毎回答えとなるランダムな値を1~3の範囲で変化させ、何回で当てられるかという内容にしました。
正解するまでループし続けるような処理は更新処理を必要としないので、for文よりもwhile文で書いた方がすっきりします。

let ans = 0;
let cnt = 0;

do
{
    // ランダムな正解値の更新
    ans = Math.floor(Math.random() * 3) + 1;
    cnt++;
} while( parseInt(prompt('Please enter a number.')) === ans );

alert('Number of your challenges: ' + cnt);

break文とcontinue文

break文continue文は、繰り返し処理をより便利に扱うために用いられます。
break文はすでに何度か登場しているように、現在の処理ブロックを抜け出すために使用します。
continue文は、そのブロックのcontinue文以下のコードをスキップするために使用します。

cnt = 0;

while( 1 )
{
    if ( cnt === 11 )
    {
         alert('Break!');
         break;
    }

    if ( cnt % 5 === 0 )
    {
         alert('Continue!');
         cnt++;
         continue;
    }

    alert(cnt);
    cnt++;
}

エラーハンドリング

エラーハンドリングは順次・分岐・反復の制御構造には含まれないものの、重要な処理となっています。

エラーとは、コンピュータがプログラムを正常に実行できなくなり、中断する処理のことです。
これはプログラムの構文に間違いがあったり、参照しようとした変数が存在しなかったりした場合に発生します。

プログラミングを始めたばかりの頃はエラーが怖く感じたり、エラーが解決できずに挫折する、ということもあるかもしれません。
しかし、エラーは正しいプログラムを書くのを手助けするために存在します。
エラー文を丁寧に読み、何度もエラーにぶつかることで、だんだんと慣れていきますので頑張りましょう!

ここではエラーを解決する方法ではなく、自分でエラーをハンドリング、つまりエラーを利用する方法を紹介します。

エラーの種類

まずはエラーの種類を見ていきます。
どのエラーがどのような意味を持っているのかを知っておくことで、エラー解決の手助けにもなることでしょう。

エラー概要
SyntaxError構文エラー。プログラムの書き方が間違っている。
ReferenceError参照エラー。存在しない変数や定数にアクセスしようとしている。
RangeError範囲エラー。数値を受け取る関数において不正な範囲の値が与えられている。
TypeError型エラー。その型では実行できない処理を行おうとしている。
URIErrorURIエラー。不正なURIを利用しようとしている。

throw文

throw文エラーを明示的に発生させるために使用します。
自分が実装している処理の中で、エラーを発生させたい場合などに使い、エラー以外を投げることもできます。

throw Error('My error message.');

try文

try文エラーを補足して処理するための構文です。
tryブロックの中身をチェックして、エラーがあった場合にはcatch節内の処理を実行します。
また、後処理を行いたい場合はfinally節の中に処理を記述します。

finally節は任意なので、絶対に記述しなければいけないわけではありません。

if-else文によく似ていますが、用途が違いますのでしっかり使い分けましょう。

try
{
    // エラーをチェックしたい処理
}
catch ( エラー )
{
    // エラーが発生した場合の処理(例外処理)
}
finally
{
    // エラーの発生状況に関わらずに最後に実行する処理
}

使用用途としては、ログを出力したり、リカバリを行ったり、処理をリトライしたりすることが多いです。
また、catch節の中で補足されたエラーはスキップされ、プログラムは継続して実行されます。
そのため、エラーとして扱いたい場合には明示的にthrowする必要があります。

まとめ

JavaScriptの様々な制御構文について見てきました。
基本の制御構文は順次・分岐・反復です。

条件分岐には、主にif文を用います。
また、対象となる変数と様々な値を比較して条件分岐したい場合にはswitch文が便利です。

繰り返し処理(反復処理)には、主にfor文を用います。
また、更新処理を必要としないような条件でループしたい場合はwhile文が便利です。

さらに、エラーハンドリングの方法についても紹介しました。
こちらはある程度大規模な開発でないと使用することはないかもしれませんが、知識としては知っておいた方がよいと思います。

ひとりではなかなかプログラミングの学習が続かない、未経験だから不安が多い、という方はプログラミングスクールを利用してみるのも有効です。
本物のエンジニアに学ぶことで、時間がない方でも最短でスキルを身につけることができます。
現役エンジニアのパーソナルメンターからマンツーマンで学べる

お悩みの方は、まずは無料キャリアカウンセリングにお申込みください。

関連記事

この記事のタグ