CURRICULUM  /  LAYER 01  /  CHAPTER 04

JavaScriptを読む

HTMLが「意味」、CSSが「見た目」なら、JavaScriptは「動き」です。

ボタンを押したら何かが起きる。

入力したら何かが変わる。

この「起きる」「変わる」を書き表すための言葉を、これから一つずつ読み解いていきます。

JavaScriptは何をしている言語なのか

あなたがウェブサイトを開いて、ボタンをクリックしたら、画面の一部がふわっと変わった。

入力欄に文字を打ち込んだら、リアルタイムで文字数が表示された。

送信ボタンを押したら、ページを遷移せずにメッセージが表示された。

こういう「動き」を作っているのが、JavaScriptです。

ブラウザの中に住んでいて、HTMLの内容を読み書きしたり、ユーザーの操作に反応したりする。

それがJavaScriptの仕事です。

— Key Concept

JavaScriptは「ブラウザの中で動くプログラミング言語」です。

HTMLを表示した後、そのHTMLに手を加えたり、ユーザーの操作を受けて何かを実行したりできる。

サーバーに頼らず、その場ですぐに反応できるのが強みです。

まずは最小の例を読んでみる

言葉の説明をする前に、いきなり実物を見てもらいます。

次のコードは、ボタンをクリックしたら画面のメッセージが変わるという、ごく小さな例です。

<p id="message">こんにちは</p>
<button id="greet-btn">押してね</button>

<script>
  const btn = document.getElementById("greet-btn");
  btn.addEventListener("click", function() {
    const msg = document.getElementById("message");
    msg.textContent = "こんばんは!";
  });
</script>

最初に見ると、呪文のようですよね。

でも、落ち着いて一行ずつラベルのように読んでいくと、ちゃんと意味があります。

この先の説明を読んだあとで、もう一度このコードに戻ってくると、ぐっと親しみが湧くはずです。

変数 ─ 「あとで使うもの」に名前を付ける

プログラミングで一番最初に出てくる概念が、変数です。

変数というと難しく聞こえますが、要するに「後で何度も使うものに、名前を付けて取っておく」ための仕組みです。

// 「name という名前で、'山田' という文字列を取っておく」
const name = "山田";

// 取っておいた name を、後で使える
console.log(name);  // → 山田 と表示される

const というキーワードは「これから変数を作りますよ」という合図です。

その後に名前を書き、= で値を結び付けます。

数学の「等しい」ではなく、「右の値を左の名前に入れる」という意味だと思ってください。

JavaScriptには変数を作る方法が3つあります(constletvar)。

違いは少しずつありますが、初心者のうちは、原則 const を使うと覚えてOKです。

途中で値を書き換える必要があるときだけ let を使い、var は古い書き方なので新しいコードでは避けましょう。

// const: 一度決めたら変えない(基本これ)
const pi = 3.14;

// let: あとで値を書き換える必要があるとき
let count = 0;
count = count + 1;  // ← constだとこれができない

値にはいくつかの種類がある

変数に入れる値には、いくつかの種類(型)があります。

入門段階では、次の4つを押さえれば十分です。

const name    = "山田";        // 文字列(string)─ ダブルかシングルのクォートで囲む
const age     = 42;            // 数値(number)─ そのまま書く
const isAdmin = true;          // 真偽値(boolean)─ true または false
const fruits  = ["りんご", "みかん"]; // 配列 ─ 複数の値をまとめて入れる箱

文字列はクォート("')で囲むのがルールです。

クォートを忘れると、JavaScriptはそれを「変数名」だと勘違いして、怒られます。

これが初心者のつまずきあるあるです。

関数 ─ 「ひとまとまりの処理」に名前を付ける

変数が「値に名前を付ける仕組み」なら、関数は「処理のひとまとまりに名前を付ける仕組み」です。

同じ処理を何度も書かずに済ませたり、複雑な処理に分かりやすい名前を付けて整理したりするために使います。

// 「greet という名前で、挨拶を表示する処理」を定義する
function greet(name) {
  console.log("こんにちは、" + name + "さん!");
}

// 定義した関数は、何度でも呼び出せる
greet("山田");  // → こんにちは、山田さん!
greet("田中");  // → こんにちは、田中さん!

用語を整理しましょう。

返り値は return というキーワードで指定します。

// 2つの数を足して、結果を返す関数
function add(a, b) {
  return a + b;
}

const sum = add(3, 5);
console.log(sum);  // → 8
— Note

モダンなJavaScriptには「アロー関数」という別の書き方もあります(const add = (a, b) => a + b;)。

見た目が違うだけで、やっていることは同じです。

最初は function のほうで頭を慣らし、慣れてきたらアロー関数も読めるようにすればOKです。

条件分岐 ─ 「もし〜なら」を書き表す

プログラムは、いつも同じことをするわけではありません。

「もしログインしていたらマイページを表示、そうでなければログインページにリダイレクト」のように、状況に応じて処理を分けたい場面がたくさんあります。

それを書くのが条件分岐です。

const age = 20;

if (age >= 18) {
  console.log("成人です");
} else {
  console.log("未成年です");
}

これは、こう読みます。

「もし age が18以上だったら、『成人です』と表示する。そうでなければ、『未成年です』と表示する」。

英語がそのまま読めれば、ほぼ日本語で追いかけられる構文です。

条件が3つ以上に分かれるときは、else if を使います。

const score = 75;

if (score >= 90) {
  console.log("優");
} else if (score >= 70) {
  console.log("良");
} else if (score >= 50) {
  console.log("可");
} else {
  console.log("不可");
}

上から順番に条件が試されて、最初にマッチしたブロックだけが実行されます。

score が75なら、「90以上か?」はNo、「70以上か?」でYesになり「良」と表示されます。

それ以降の条件はチェックされません。

比較のための記号

条件に使う記号もいくつか覚えておきましょう。

特に注意したいのは、「等しい」が == ではなく === であることです。

a === b     // 等しい(これを使う)
a !== b     // 等しくない(これを使う)
a < b       // 小なり
a > b       // 大なり
a <= b      // 以下
a >= b      // 以上

// 組み合わせ
a && b      // かつ(両方trueならtrue)
a || b      // または(どちらかがtrueならtrue)
!a          // 〜でない(trueとfalseを反転)

JavaScriptには ===== の2種類の「等しい」があるのですが、== は型の違いを曖昧に吸収してしまうため、思わぬバグの温床になります。

原則として ===(等しい)と !==(等しくない)だけを使うと覚えておくと、ほぼ事故りません。

最初の例に戻ってみる

さて、最初に見せたコードをもう一度貼ります。

今なら、ずっと読めるはずです。

const btn = document.getElementById("greet-btn");
btn.addEventListener("click", function() {
  const msg = document.getElementById("message");
  msg.textContent = "こんばんは!";
});

読み下してみます。

  1. const btn = ...:「id が greet-btn の要素を探してきて、btn という名前で取っておく」
  2. btn.addEventListener("click", function() { ... }):「btn がクリックされたら、中の処理を実行する」
  3. const msg = ...:「id が message の要素を探してきて、msg という名前で取っておく」
  4. msg.textContent = "こんばんは!":「msg の中身の文字を『こんばんは!』に書き換える」

やっていることは、「ボタンを見つけて、クリックされたらメッセージを書き換える」。

それだけのことを、変数・関数・DOM操作の組み合わせで書き表しているわけです。

document.getElementByIdaddEventListener は今はまだ呪文でOK。

「HTMLの要素を取ってくる命令」「イベントを待ち受ける命令」くらいの理解で十分です。

解読演習

— EXERCISE 01-04-A

このコードは、何を表示するか

次のJavaScriptコードを実行すると、コンソールには何が表示されますか? 上から順に、頭の中で追いかけてみてください。

function discount(price, isMember) {
  if (isMember) {
    return price * 0.8;
  } else {
    return price;
  }
}

const a = discount(1000, true);
const b = discount(1000, false);

console.log(a);
console.log(b);
解答例を見る

コンソールには、順番に 8001000 が表示されます。

discount は、価格と「会員かどうか」を受け取って、会員なら2割引き、そうでなければそのままの値段を返す関数です。

a は会員として1000円を渡しているので、1000 × 0.8 = 800。

b は非会員として1000円を渡しているので、1000のまま。

ポイントは、if (isMember) と書けるところ。

isMember はもともと真偽値(true / false)なので、わざわざ if (isMember === true) と書かなくても、そのまま条件に使えます。

これはJavaScriptらしい書き方です。

— EXERCISE 01-04-B

このコードの問題点はどこか

AIに「3つの数のうち最大のものを返す関数を書いて」と頼んだら、こんなコードが返ってきました。

動作はするのですが、プロのレビュアーの眼で見ると、気になる点がいくつかあります。

どこが微妙でしょうか?

function max3(a, b, c) {
  var result;
  if (a > b && a > c) {
    result = a;
  }
  if (b > a && b > c) {
    result = b;
  }
  if (c > a && c > b) {
    result = c;
  }
  return result;
}
解答例を見る

指摘ポイントは3つあります。

(1) var が使われている ── 現代のJavaScriptでは const または let を使うのが標準です。

var は古い書き方で、スコープ(変数が有効な範囲)の振る舞いが直感的でないため、バグの温床になります。

ここでは let result; とすべきです。

(2) 等しい値があったときに結果が返らないバグ ── 致命的な問題です。

たとえば max3(5, 5, 3) を呼ぶと、どの条件にもマッチしません。

a > b は false(5は5より大きくないため)。

b > a も false。

結果、result は未定義のまま undefined が返ります。

条件は >= を使うか、そもそも別の書き方をすべきです。

(3) 無駄な比較をしている ── if / else if / else で書けば、マッチした時点で残りの比較をスキップできます。

今の書き方では3つの if を毎回チェックしているので効率が悪い。

もっと言えば、こんなふうに書けば一発です:

function max3(a, b, c) {
  return Math.max(a, b, c);
}

AIが書いてきたコードを「動いてるからOK」で済ませると、(2)のような隠れた不具合を見逃します。

動作確認のとき、「境界ケース(同じ値、0、マイナス、空っぽ)で試したか?」を毎回自問するクセをつけましょう。

— EXERCISE 01-04-C

この == 、何が起きる?

次のコードの結果を予想してください。

JavaScriptの ===== の違いを思い出しながら読んでみてください。

console.log(0 == "");       // ①
console.log(0 === "");      // ②
console.log("1" == 1);      // ③
console.log("1" === 1);     // ④
解答例を見る

結果は順に: true / false / true / false です。

①は、== が「型の違いを無理やり揃えて比べる」という性質を持っているため、数値の0と空文字列 "" が両方とも「なんとなくゼロ相当」と見なされて true になります。

奇妙ですが、これがJavaScriptの伝統的な挙動です。

②は、===(厳密等価)を使っているので、型が違うこと(数値 vs 文字列)を正しく検出して false になります。

③も①と同じで、文字列の "1" が数値の1に変換されて比較された結果、true になります。

④は、=== なので型の違いを尊重し、false。

この混乱があるからこそ、JavaScriptの現代的な書き方では 常に ===!== を使う のがお約束になっています。

AIが書いたコードに == が出てきたら、ほぼ直す対象だと思っていいでしょう。

この章のまとめ

次の章では、いよいよサーバーサイドのPHPに入ります。

JavaScriptがブラウザの中で動く言語だとしたら、PHPはサーバーの中で動く言語。

どこが同じで、どこが違うのか。

この比較が、ウェブ全体の見通しを一段良くしてくれます。