クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【JSの基本-後編】書ける前に読む!HTML、CSS、JSの書式-5

Webサイトを形作っている言語「HTML」「CSS」「JS」。
この3言語を身につけるためには、まずはフワッとでもコード*1を読めるようになることが先決と思う。人のコードを読める(インプット)と、自分でゼロから書く(アウトプット)ときの引き出しになる。
書ける前に読む!*2と、いうことでコードを読むために理解しておくといいHTML、CSS、JSの基本書式をまとめる。

第5回は「JSの基本-後編」Webサイトの動作、変更を制御する「JS」の書式。前・後編の後編であり、本連載の最終回!

連載一覧:

目次:

第1回(Webの基礎知識)にも書いたようにJSは文書に動作や変更を加える「スクリプト言語」だ。
前・後編に分けてお送りするJS編。前回(前編)では「オブジェクト」「関数」「変数」について解説した。後編では「イベント」「制御構造」について解説する。

イベント

イベント=いつ

「イベント」は日本語文でいう「いつ」に当たる部分だ。
これまで対象(オブジェクト)の処理(プロパティ、メソッド)について触れたが、イベントを設定すれば実行のタイミングが制御できる。
「いつ(イベント)、何が(オブジェクト)、どうなる(処理)」という形になる。
イベントハンドラ」と「イベントリスナ」の2つの書き方がある。

イベントハンドラ

それではまずは「イベントハンドラ」を解説しよう。 イベントハンドラは下記のような書式になる。

//イベントハンドラ
オブジェクト.onイベント名 = 関数;

onイベント名の後にイコール=で関数をで繋ぐ。見た目は前回(前編)触れた「プロパティ」に似ている。 イベント名の前にon を付けるのが特徴だ。
例:

//DOM
var btn = document.getElementById("btn");

//イベントハンドラ
btn.onclick = function () {
    window.alert("この内容で送信します。宜しいですか?");
};

イベントハンドラの中には前回(前編)の関数で触れた「無名関数」を代入する。
イベントの関数はそこでしか実行しないことが多いため、名前がいらないのだ。(関数名が多いと、関数名の重複や干渉の原因になり得る)

  • 変数btnにid名btn*3の要素を代入している。(前回(前編)触れた「DOM」)
  • 変数profileのイベントハンドラonclickにアラートの関数を代入している。
  • clickイベントは文字通り「クリックした時」のイベント。
  • id名btnの要素をクリックすると文字列「この内容で送信します。宜しいですか?」がアラート表示される。

関数読み込み(イベントハンドラ)

なお、関数を別の用途にも使いたい場合は外に書いてイベントに読み込むのもいいだろう。
ただしイベント外の関数を読み込む場合は、イベント内の関数名にはカッコ( )を付けないルールなので注意。

//DOM
var btn = document.getElementById("btn");

//関数(イベントの外)
function ok () {
    window.alert( "この内容で送信します。宜しいですか?");
}

//イベントハンドラ
//関数読み込み(カッコを付けない!)
btn.onclick = ok;

onclickの値に入れる関数名okok()ではない!

イベントハンドラは一度きり

なお、イベントハンドラは同じオブジェクトに複数設定すると最後の一度しか実行されない。
例:

//DOM
var kazoeuta = document.getElementById("kazoeuta");

//イベントハンドラ1(実行されない…)
kazoeuta.onclick = function () {
    window.alert( "一本でもニンジン");
};
//イベントハンドラ2(実行されない…)
kazoeuta.onclick = function () {
    window.alert( "二足でもサンダル");
};
//イベントハンドラ3(実行される!)
kazoeuta.onclick = function () {
    window.alert( "三槽でもヨット");
};

kazoeutaに対して3つイベントハンドラを設定したところ、最後の「三槽でもヨット」しかアラート表示されない。

イベントハンドラはシンプルな記法なので、あらかじめ1度しか実行しないとわかっている時に使用するといいかもしれない。

イベントリスナ

次はイベントリスナについて解説しよう。
イベントリスナは下記のような書式になる。

//イベントリスナ
オブジェクト.addEventListener("イベント名", 関数, false);

addEventListenerの後ろにカッコ( )を付けて、中に引数を3つ入れる。こちらは見た目が前回(前編)触れた「メソッド」に似ている。
引数1のイベント名はダブルコーテーション" "で囲う。引数2は先ほどの「イベンドハンドラ」と同じく「無名関数」。引数3にはfalse*4を入れる。
例:

//DOM
var btn = document.getElementById("btn");

//イベントリスナ
btn.addEventListener("click", function () {
window.alert( "この内容で送信します。宜しいですか?")}, false);

イベントリスナ内の関数も無名関数。

関数読み込み(イベントリスナ)

先ほどの「イベントハンドラ」同様に、イベントリスナもイベント外部の関数を読み込むときは関数名にカッコ( )を付けない。

//DOM
var btn = document.getElementById(" btn");

//関数(イベントの外)
function ok () {
window.alert( "この内容で送信します。宜しいですか?")}

//イベントリスナ
//関数読み込み(カッコを付けない!)
 btn.addEventListener("click", ok, false);

イベント名"click"の後の関数名okok()ではない!

イベントリスナは何度でも

先ほどのイベントハンドラは同じオブジェクトに複数イベントを設定しても最後の一度しか実行されなかった。 イベントリスナの場合は、同じオブジェクトに複数設定すると全てが実行される。

//DOM
var kazoeuta = document.getElementById(" kazoeuta");

//イベントリスナ1(実行される!)
 kazoeuta.addEventListener("click", function () {
window.alert( "一本でもニンジン")}, false);

//イベントリスナ2(実行される!)
 kazoeuta.addEventListener("click", function () {
window.alert( "二足でもサンダル")}, false);

//イベントリスナ3(実行される!)
 kazoeuta.addEventListener("click", function () {
window.alert( "三槽でもヨット")}, false);

先ほどのイベントハンドラと同じくkazoeutaに対して3つイベントリスナを設定したところ「一本でも〜」から「三槽でも〜」まで全てアラート表示される。
そのため、イベントリスナの方がイベントハンドラより複雑な設定ができる。

制御構造

分岐と反復

次は「制御構造」を解説する。
制御構造は「○○なら○○する」という感じで「条件」を満たしたときに処理を実行する仕組み。
プログラミング言語には以下の3つの構造があり、制御構造は「分岐」と「反復」*5だ。

  • 順次:コードを上から下に順番に処理していく。(これまで触れてきた内容)
  • 分岐:条件によって「○○の場合はこうする」という風に処理が分岐する。
  • 反復:条件によって「○○の場合はこれを繰り返す」という風に処理を反復する。

また、制御構造同士を組み合わせれば「もし○○なら○○を繰り返す」など、さらに多彩な処理ができるようになる。
それでは主な制御構造を見ていこう。

if文(分岐)

「if文」は「分岐」処理だ。和訳が「もし」なのでイメージしやすい。

if (条件式) {ブロック文}

if文の形は前回(前編)に出てきた「無名関数」と良く似ている。
functionだった冒頭がifになり、カッコ( )の中には「条件式」が入る。
カッコの次の波カッコ{ }は「ブロック文」で波カッコの後はセミコロン;が付かない。

それではブロック文の内容を見ていこう。if文には以下の4パターンがある。

/*もし条件式なら処理をする。
(それ以外は何もしない)*/
if (条件式) {
    処理
}

/*もし条件式なら処理1をする。
それ以外は処理2をする*/
if (条件式) {
    処理1
} else {
    処理2
}

/*もし条件式1なら処理1をする。
もし条件式2なら処理2をする(これを繰り返す)
それ以外は処理4をする*/
if (条件式1) {
    処理1
} else if (条件式2) {
    処理2
} else if (条件式 3) {
    処理3
} else {
    処理4
}

/*もし条件式1なら処理1をする。
もし条件式2なら処理2をする(これを繰り返す)
(それ以外は何もしない)*/
if (条件式1) {
    処理
} else if (条件式2) {
    処理
} else if (条件式3) {
    処理
} 
  • elseは「それ以外すべて」。
  • else ifif以外の「条件」。
  • elseがないif文は処理を終了してif文を抜ける。

例:

var age = 37

if (age >= 55) {
    window.alert("あなたは年配です");
} else if (age >= 45) {
    window.alert("あなたはアラフィフです");
} else if (age >= 35) {
    window.alert("あなたはアラフォーです");
} else if (age >= 25) {
    window.alert("あなたはアラサーです");
} else {
    window.alert("あなたは若者です");
}

//結果 あなたはアラフォーです

>=は「以上」という意味で「比較演算子*6」という記号の一つ。 変数ageの内容が25以上なら「アラサー」、35以上なら「アラフォー」、45以上なら「アラフィフ」、55以上は全て「年配」。
それ以外は全て24以下のため「若者」とアラート表示する。

switch文(分岐)

switch文も「分岐」処理。
if文は条件を書く順番によって優先度が変わるため、書き順をよく考えないといけないが、switchは条件が並列している。

switch (条件式) {ブロック文}

全体的な構成はif文と変わらない。ブロック文の内容を見ていく。

//「それ以外」処理なし
switch (条件式) {
    case 分岐1: 処理1; break;
    case 分岐2: 処理2; break;
    case 分岐3: 処理3; break;
}

//「それ以外」処理あり
switch (条件式) {
    case 分岐1: 処理1; break;
    case 分岐2: 処理2; break;
    case 分岐3: 処理3; break;
    default: 処理4; break;
}
  • caseの後に分岐の値を入れコロン;を付ける。処理を書いてセミコロン;を付ける。
  • 処理ごとに最後にbreak;が必要なので注意。break;で処理の区切りが判断される。
  • default:はif文の「それ以外」elseに当たる。

例:

var month = 4

switch (month) {
    case 1: 
        window.alert("1月は正月で酒が飲めぞ!");
        ; break;
    case 2: 
        window.alert("2月は豆まきで酒が飲めるぞ!");
        ; break;
    case 3: 
        window.alert("3月はひな祭りで酒が飲めるぞ!");
        ; break;
    case 4: 
        window.alert("4月は花見で酒が飲めるぞ!");
        ; break;
    case 5: 
        window.alert("5月は子供の日で酒が飲めるぞ!");
        ; break;
    case 6: 
        window.alert("6月は田植えで酒が飲めるぞ!");
        ; break;
    case 7: 
        window.alert("7月は七夕で酒が飲めるぞ!");
        ; break;
    case 8: 
        window.alert("8月は暑いから酒が飲めるぞ!");
        ; break;
    case 9: 
        window.alert("9月は台風で酒が飲めるぞ!");
        ; break;
    case 10: 
        window.alert("10月は運動会で酒がめるぞ!");
        ; break;
    case 11: 
        window.alert("11月は何でもないけど酒が飲めるぞ!");
        ; break;
    case 12: 
        window.alert("12月はドサクサで酒が飲めるぞ!");
        ; break;
    default:
        window.alert("そんな月は無いけど酒が飲めるぞ!");
}

//結果 4月は花見で酒が飲めるぞ!
  • 変数monthがswitchの条件式に入る。
  • 値が1から12まで並列にで変数と一致する物を選ぶ。それ以外はdefaultをアラート表示する。
  • 例では変数monthの値に4が入っているため「4月は花見で酒が飲めるぞ!」がアラート表示する。

for文(反復)

for文は「反復」処理だ。全体構成はif文、switch文と変わらない。

for (条件式) {ブロック文}

もう少し詳しく見ていこう。

for (初期化式; 条件式; 増減式) {
    処理
}

for文の場合は山カッコ{ }の中よりもカッコ( )の中の方が複雑だ。
引数のようなカンマ,ではなくセミコロン;で3つの式が繋がっている。 「初期化式」には最初の値、「条件式」は最後の値、「増減式」は値の増え方を書く。
例:

//配列
var soup = ["醤油", "味噌", "塩"];

for (var i =0; i < 3; i++) {
    window.alert(soup[i] + "ラーメンいかがっすかー?"); 
}

「醤油ラーメンいかがっすかー?」「味噌ラーメンいかがっすかー?」「塩ラーメンいかがっすかー?」と3回アラート表示する。

  • 変数soupは配列でスープの種類が3つ入っている。
  • 初期化式にあるfor文の変数iはfor文の中だけで使う簡易的な変数。数値0がスタート値。
  • 条件式では変数iが3以下<の間に実行、という条件が入っている。
  • 増減式は変数iの数値の増え方。++第4回の四則演算でも触れた「算術演算子」の中の1種でインクリメント演算子という。数値が1ずつ増えることを意味する。*7
  • ブロック文の中で、配列を呼び出すsoup[ ]の中に変数iを入れているsoup[i]

このままだと、メニュー数が増えるたびに条件式の3を打ち換えないといけないが、以下の対応策がある。

//配列
var soup = ["醤油", "味噌", "塩", "豚骨"];
var len = soup.length; //(配列数)

//lengthに変更
for (var i =0; i < len; i++) {
    window.alert(soup[i] + "ラーメンいかがっすかー?"); 
}

lengthプロパティは「長さ」という意味で、配列の数を取得する。
これを変数lenに代入し、for文の条件式に組み込むと、配列数文繰り返してくれる。
これで今後メニューが増減しても、回数を打ち替えずに済む。

while文(反復)

while文も「反復」処理。基本構成は他の制御構造と同じだ。

//while文
while (条件式) {ブロック文}

whileの中の引数にはfor文の「条件式」だけがある。「初期化式」は外に変数として設定している。「増減式」はブロックの中にある。

//while文
var i=初期化式

while (条件式)  {
    処理
    増減式
}

例:

//配列
var soup = ["醤油", "味噌", "塩"];

//初期化式
var i=0;

//while文
while (i < 3) {
    window.alert(soup[i] + "ラーメンいかがっすかー?"); 
    i++
}

結果は先ほどのfor文と同じだ。*8
「醤油ラーメンいかがっすかー?」「味噌ラーメンいかがっすかー?」「塩ラーメンいかがっすかー?」と3回アラート表示する。

JSのネスト構造

JSはこれまで出てきた前回(前編)の「変数」「関数」や今回の「イベント」「制御構造」を組みわせてプログラミングされている。
特に「変数」や「関数」は定義と実行が離れた場所に書かれているので位置関係を意識したい。

もう一つ意識したいのは閉じカッコだ。

var = aaa;
var = aaa;
var = aaa;
function aaa (aa,aaaa){
    var aaa = [aaa,
            123,
            aaa(function(){
                aaa.aaa (aa,aa,123);
                var aaa = function(){
                var a = aa (aa, aa(
                    if (aa=aa) {
                        for (0;0>0;0) {
                            aaa.aaa(aa,aa,123);
                            aaa.aaa(aa,aa,123);
                        }
                    } else if(aa=aa){
                        for(0;0>0;0){
                            aaa.aaa(aa,aa,123);
                            aaa.aaa(aa,aa,123);
                        }
                    });
                );
                return aaa;
                };
            });
        ];
}

なんだかこんな感じにネストがどんどん深くなって)}];みたいな閉じカッコの塊がそこらにある。*9
コードを読むときには、どの閉じカッコがどのカッコに当たるか理解できると、閉じカッコの抜けやダブりなどのエラーも見つけやすくなる。
(また、ネストは前回(前編)に触れた「スコープ」にも関わる)

JSサンプル

最後に、第3回(CSSの基礎)の「CSSサンプル」にこれまでの機能を使ったJSのコードを追加してみた。

// イベントリスナ(DOM読み込み)
window.addEventListener('load', function() {

    // 変数定義(DOM取得)
    var target = document.querySelector("#profile img");

    // 関数定義
    function hakken () {

        // 配列
        var serif = ["隠しボタンを見つけてくれてありがとう。私の名前は“Atama”です。",
                     "何かご用はありませんか?", 
                     "私を閉じますか?", 
                     "本当に閉じますか?",
                     "もう少しあなたとお話ししたいです。それでも閉じますか?",
                     "……わかりました。ごきげんよう。"];
        var len = serif.length; //(配列数)

        // 制御構造(反復)
        for (var i =0; i < len; i++) {
            window.alert(serif[i]); 
        }
    }

    // イベントリスナ(クリック)
    target.addEventListener("click", hakken, false);
    
});

処理の詳細な説明は省くが、全体がどのような動きになっているか説明する。

  • イベントリスナでwindow(DOM)の読み込みが終わったら処理を実行。
  • 変数targetにDOMのCSSセレクタ#profile img"を代入。
  • 関数hakkenの配列serifにアラートに表示したいセリフを入れる。
  • 変数lenで配列serifの配列数を取得。
  • for文で配列serifのセリフをalertメソッドの引数に読み込んで、変数lenの配列回数分アラートを表示。
  • イベントリスナに変数targetと関数hakkenを組み込みclickイベントで起動させる。

※2020/07/24追記:処理全体をloadイベントで囲んだ(CodePenだと気付かなかったのだが、DOM#targetがwindow(DOM)読み込み後じゃないと取得できなかっため*10

こちらが表示サンプル。プロフィールの画像をクリックすると、人口知能「Atama」が起動する。

「Result」タブを「JS」タブに切り替えると上記のコードが書かれている。

GitHubにソースコードを公開(2020/07/24追加

※参考:HTML_CSS_JS_formats/gaibu.js at master · ryo-i/HTML_CSS_JS_formats · GitHub

プレビュー画面

※参考:イイダリョウ | クモのようにコツコツと

最後に

読めるぞ!私にもJSが読める!!*11」と、なっていただけただろうか。
コンピュータが処理の判断として拾う記号やキーワードは、人間がコードを読むための「目印」にもなることがイメージできたかと思う。
ちょっとした宝探し気分で気軽にコードを読んで見てもらいたい。

本連載で触れた内容はHTML、CSS、JSの基本書式。詳細については個別の機会にまた触れていきたいと思う。
また、本連載がきっかけで自分でもちょっとコードを書いてみようかなー、なんて思っちゃたりしたそこのあなた!ぜひ第1回(Webの基礎知識)の「コードを書きたくなったら…」をご覧いただきたい。

※参考: 【Webの基礎知識】書ける前に読む!HTML、CSS、JSの書式-1 idr-zz.hatenablog.com


本連載は、これからWebサイト制作を始めてみたい方を念頭に、当ブログの記事中に出てくるWeb系の単語の「出発点」になることを目指して書きました。
なるべく平易な言葉で、段階的な説明を心がけたつもりです。(書きながら自分自身の復習にもなりました)
もし内容に不明点、おかしい点などあれば(優しく)ご指摘いただけると幸いです。


【HTML、CSS、JSの書式】まとめ
qiita.com

*1:ソースコード。人が書いたコンピュータへの命令のこと。

*2:某胃腸薬

*3:btnはbuttonの略でボタンによく付けられる名前

*4:真偽値(true、false)

*5:ループ、繰り返し、とも言われる。

*6:他に==(等しい)、!=(等しくない)、<=(以上)などがある。

*7:ちなみに1ずつ減らすデクリメント演算子「--」もある

*8:他にも条件に関係なく最初に1回処理を実行する「do while文」などもあり、while文の方がfor文より細かい制御ができる。

*9:リーダブルじゃないコードというみたいです…

*10:jsリンクをbodyの閉じタグの直前に書く、という方法もある

*11:赤い彗星