関数 — 再利用可能なコードブロック - ウェブ開発を学ぶ

関数 — 再利用可能なコードブロック
==================

* 前のページ
* Overview: Building blocks
* 次のページ

コーディングにおいて、不可欠なコンセプトが**関数**です。関数を使用することで、特定のタスクをこなすコードを定義し、保持しておいて、いつでも簡単なコマンドで呼び出すことを可能にしてくれます。同じコードを何度も打たなければならないよりとっても簡単です。この記事では関数の書き方や、関数を実行する方法、定義の仕方、スコープ、引数といった関数に関する基礎を学びます。

| 前提知識: | 基本的なコンピューターの知識、HTML と CSS への理解、JavaScript の第一歩。 |
| --- | --- |
| 目的: | JavaScript の関数についての基礎を理解する。 |

関数はどこにありますか？
------------

JavaScript の中で、関数はあらゆるところに見つかるでしょう。実際、これまでのところすべての場面で関数を使用してきました。これについてはあまり触れてきませんでした。しかし、今こそ明確に関数について話し始め、本当に構文を探索する時期です。

一対のかっこ — `()` — の機能である JavaScript の構造を使用するほとんどの場合、そして for ループ、while と do ... while ループ、または if..else 文のような一般的な組み込みの言語構造を使用**していない**場合、あなたは関数を使用していることになります。

ブラウザー組み込み関数
-----------

このコースではブラウザーに組込まれた関数をたくさん使ってきました。毎回テキスト文字列を操作したときには、こんな風に:

```js
let myText = "I am a string";
let newString = myText.replace("string", "sausage");
console.log(newString);
// the replace() string function takes a string,
// replaces one substring with another, and returns
// a new string with the replacement made
```

あるいは毎回配列を操作したときには:

```js
let myArray = ["I", "love", "chocolate", "frogs"];
let madeAString = myArray.join(" ");
console.log(madeAString);
// the join() function takes an array, joins
// all the array items together into a single
// string, and returns this new string
```

また毎回乱数を作成したときには:

```js
let myNumber = Math.random();
// the random() function generates a random
// number between 0 and 1, and returns that
// number
```

...関数を使っていたのです!

**メモ:** これらの機能に慣れるために、必要なときにはこういった行をあなたのブラウザーの JavaScript コンソールにいつでも入力してみてください。

JavaScript 言語にはたくさんの組込み関数があるので、いろいろあるあなたのやりたい事を、全部をあなた自身で書かなくてもすみます。実は、あなたが呼び出して起動(走らせたり実行する事の別の言い方)するコードのいくつかは、JavaScript では書けない、ブラウザー組込み関数です — こういった関数の多くは背後のブラウザーのコードを呼び出していて、これらは JavaScript のようなウェブ言語ではなく、大半が C++のような低レベルのシステム言語で書かれています。

ブラウザー関数のいくつかは JavaScript 言語の核に含まれない事を心に留めておいてください — いくつかはブラウザー API の一部として定義されていて、もっと多くの機能を提供すべくデフォルトの言語の上で構築されています(詳しくは私たちのコースのこの以前のセクションを見てください)。ブラウザー API のもっと詳しい使い方については、後の方のモジュールで見ていく事になるでしょう。

関数とメソッド
-------

オブジェクトの**メソッド**の一部を、プログラマーは**関数**として呼び出します。構成された JavaScript オブジェクト内部の働きについては、まだ知る必要はありません — この後のモジュールで、オブジェクト内部の働きや自分でオブジェクトを作る方法について教える段階になってから覚えれば大丈夫です。今のところは、ウェブのあちこちにある関連したリソースを見ていると、メソッドと関数が混在している事があるとわかってもらいたいだけです。

これまで利用してきた組込み関数は両方です: 関数でありメソッドでもあります。組み込みオブジェクトとそのメソッドと同様に、組み込み関数の一覧をこちらで確認できます。

このコースのここまででもたくさんのカスタム関数を見てきました — ブラウザーの内部でではなくあなたのコードの中で定義された関数です。独自の名前の直後にカッコがついてるものを見かけたら、それはカスタム関数を使っているという事です。繰返しの記事で出てきた random-canvas-circles.html の例(ソースコードはこちら)では、独自に作った `draw()` 関数が含まれていました。こんなやつです:

```js
function draw() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
    ctx.fill();
  }
}
```

この関数は、`<canvas>` 要素の内にランダムな円を 100 描きます。同じ事をやりたい時には、いつでもこんな具合に関数を起動するだけです

```js
draw();
```

繰り返しをする毎に何度も同じコードを書き上げるのではなく。関数にはあなたが書きたいどんなコードでも含められます — 関数の中から他の関数を呼ぶことだってできます。例に挙げた上の関数では、`random()`関数を 3 回呼んでいて、random 関数は以下のコードで定義されています:

```js
function random(number) {
  return Math.floor(Math.random() \* number);
}
```

ブラウザー組込みの Math.random() は 0 から 1 までの間の 10 進数の乱数を作成するだけなので、私たちにはこの関数が必要でした。私たちは 0 から指定した数にわたる乱数が欲しかったのです。

関数の呼び出し
-------

もうよくご存知でしょう、でも念のため … 定義した後で実際に関数を使うには、関数を走らせ — あるいは起動し — なければなりません。これはコードのどこかに関数の名前、直後にカッコの組を書けばできます。

```js
function myFunction() {
  alert("hello");
}

myFunction();
// calls the function once
```

匿名関数
----

ちょっと違う形式で定義されて起動される関数を見かける事があるでしょう。ここまでは関数をこのように作ってきました:

```js
function myFunction() {
  alert("hello");
}
```

でも名前のない関数を作る事もできます:

```js
function() {
  alert('hello');
}
```

これは**匿名関数**と呼ばれます — 名前がないんです! それだけでは何もしません。匿名関数はよくイベントハンドラで使われていて、例えば以下では関連づけられたボタンがクリックされるたび、関数の中のコードが走ります:

```js
const myButton = document.querySelector("button");

myButton.onclick = function () {
  alert("hello");
};
```

上の例では、ページの中に選択してクリックするための`<button>`要素が存在しなければならないでしょう。あなたはこのような例をここまでのコースで見てきましたし、ここから先の記事でもっと学習し、使い方を見ていく事になります。

匿名関数を変数の値として代入する事もできます:

```js
const myGreeting = function () {
  alert("hello");
};
```

この関数は次のように起動できます:

```js
myGreeting();
```

関数に名前をつけたような効果があります。また関数を複数の変数の値として代入する事もできます:

```js
let anotherGreeting = myGreeting;
```

結果、この関数はどちらの方法でも起動できます

```js
myGreeting();
anotherGreeting();
```

ですがこれは混乱するだけなので、やらないように! 関数を作成するときはこの形式でやった方が良いです:

```js
function myGreeting() {
  alert("hello");
}
```

匿名関数は主にイベント発火 — ボタンがクリックされたとか — のレスポンスとして、一連のコードを走らせるだけのような場合に、イベントハンドラとして使われます。くりかえしですが、こんな具合です:

```js
myButton.onclick = function () {
  alert("hello");
  // I can put as much code
  // inside here as I want
};
```

関数の引数
-----

関数には実行する時に**引数**が必要なものがあります — 関数のカッコとカッコの間に書かなければならない値で、関数が正しい仕事をするのに必要とされます。

**メモ:** 引数は、パラメーター、プロパティ、アトリビュート（属性）などと呼ばれる場合もあります。

例えばブラウザー組込み関数 Math.random() は引数を必要としません。呼ばれるといつも 0 から 1 までの乱数を返します:

```js
let myNumber = Math.random();
```

ですがブラウザー組込みの文字列関数 replace() は二つの引数が必要です — 主文字列から探すべき部分文字列と、部分文字列を置換する文字列です:

```js
let myText = "I am a string";
let newString = myText.replace("string", "sausage");
```

**メモ:** 複数の引数を指定するときは、カンマで区切って書きます

引数には省略可能 — 書かなくても良い — なものもある事に触れておくべきでしょう。省略された場合、関数はだいたいデフォルトに規定された動作を行ないます。例えば、配列の join() 関数のパラメータは省略可能です:

```js
let myArray = ["I", "love", "chocolate", "frogs"];
let madeAString = myArray.join(" ");
// returns 'I love chocolate frogs'
let madeAString = myArray.join();
// returns 'I,love,chocolate,frogs'
```

もし結合/区切り文字を指定する引数が省略された場合、デフォルトとしてカンマが使われます。

関数のスコープと競合
----------

スコープという言葉について説明しておきましょう — 関数を扱う際にはとても大切な概念です。関数を作成するとき、関数の中で定義されている変数や関数は、内部でそれぞれ独自の**スコープ**というものを持ちます。これはそれぞれが独自の小部屋に閉じ込められていて、別の関数の内部から、あるいはこの関数の外部のコードから触れられくなる事を意味しています。

あなたのすべての関数の外側、一番の外側を、**グローバルスコープ**と呼びます。グローバルスコープで定義された値はすべて、コードのどこからでもアクセスできます。

JavaScript がこう作られているのにはいくつも理由があります — が、主な理由はセキュリティと組織化のためです。時には変数にコードのどこからでもアクセスされないようにしたい場合もあるでしょう — どこかから呼び込んだ外部スクリプトが、あなたのコードをおかしくして問題を起す場合があるかもしれません。別の場所でたまたま同じ名前の変数を使っていて、衝突していたために。これは悪意をもってわざとやっている場合や、単なる偶然の場合もあります。

そうですね、例えばある HTML ファイルが二つの外部 JavaScript ファイルを呼び出しているとして、そのどちらも同じ名前の変数と関数を定義しているとします:

```html
<!-- Excerpt from my HTML -->
<script src="first.js"></script>
<script src="second.js"></script>
<script>
 greeting();
</script>
```

```js
// first.js
let name = "Chris";
function greeting() {
  alert("Hello " + name + ": welcome to our company.");
}
```

```js
// second.js
let name = "Zaptec";
function greeting() {
  alert("Our company is called " + name + ".");
}
```

あなたが呼び出したいのはどっちも `greeting()`関数ですが、あなたには `first.js` ファイルの `greeting()` 関数しかアクセスできません(2 つ目は無視されます)。加えて、`second.js` ファイルで `let` キーワードで `name` 変数に 2 度目の定義をしようとするとエラーになります。

**メモ:** この例を GitHub でライブ実行 できます(ソースコードはこちら).

あなたのコードの部品を関数の中に隔離するとこのような問題を避けられるので、これが一番良いやりかたと考えられています。

これは動物園みたいなものです。ライオン、シマウマ、トラ、ペンギンはそれぞれの檻の中にいて、それぞれの檻の中のものにしか触れられません — 関数のスコープと同じ事です。もし彼等が他の檻の中に侵入できたら問題が起きることでしょう。良くて、知らない住人に囲まれて気まずい思いをする — 寒くて水だらけのペンギンの檻に入ったライオンやトラは酷い気分になるでしょう。最悪の場合、ライオンやトラはペンギンを食べてみようとするかも!

![](/ja/docs/Learn/JavaScript/Building_blocks/Functions/MDN-mozilla-zoo.png)

動物園の管理人はグローバルスコープみたいなものです — 管理人はすべての檻の鍵を持っていて、エサを補充し、動物にうんざりし、などなど。

### アクティブラーニング: スコープで遊んでみよう

スコープを示すための実際の例を見てみましょう。

1. まず function-scope.html の例のローカルコピーを作成します。これには `a()` と `b()` という 2 つの関数と、`x`、`y`、`z` の 3 つの変数が含まれます。これらの変数のうち 2 つは関数内で定義され、もう 1 つはグローバルスコープ内で定義されます。また `output()` という 3 番目の関数も含まれています。この関数は単一のパラメータを取り、ページの段落に出力します
2. ブラウザーとテキストエディターでサンプルを開きます
3. ブラウザーの開発者ツールで JavaScript コンソールを開きます。JavaScript コンソールで、次のコマンドを入力します。

```js
output(x);
```

変数 x の出力値が画面に表示されるはずです。
4. コンソールに次のように入力してみてください

```js
output(y);
output(z);
```

どちらも、"ReferenceError: y is not defined"の一行のエラーが返されるはずです。なぜでしょうか？ 関数スコープのため、つまり `y` と `z` は `a()` と `b()` 関数の中でロックされているので、global スコープから呼び出されたときには `output()` はそれらにアクセスできません。
5. しかし、別の関数の中から呼び出されたときはどうでしょうか？ `a()` と `b()` を次のように編集してみてください：

```js
function a() {
  let y = 2;
  output(y);
}

function b() {
  let z = 3;
  output(z);
}
```

コードを保存してブラウザーに再ロードしてから、JavaScript コンソールから `a()` と `b()` 関数を呼び出してみてください。

```js
a();
b();
```

ページに `y` と `z` の値の出力が表示されます。`output()` 関数が他の関数の中、つまり表示される変数が定義されているのと同じスコープでそれぞれ呼び出されているので、これはうまくいきます。`output()` 自体はグローバルスコープで定義されているので、どこからでも利用できます。
6. 今度は次のようにコードを更新してみてください：

```js
function a() {
  let y = 2;
  output(x);
}

function b() {
  let z = 3;
  output(x);
}
```

保存してもう一度読み込み、JavaScript コンソールでもう一度試してみてください：

```js
a();
b();
```

`a()` と `b()` の両方の呼び出しは `x` の値、つまり 1 が出力されます。これは `x` がグローバル変数であり、すべてのコード内どこでも利用可能であるため、`output()` の呼び出しが `x` と同じスコープではなくてもうまく動きます。
7. 最後に、次のようにコードを更新してみてください：

```js
function a() {
  let y = 2;
  output(z);
}

function b() {
  let z = 3;
  output(y);
}
```

保存してもう一度読み込み、JavaScript コンソールでもう一度試してみてください：

```js
a();
b();
```

今度は `a()` と `b()` の両方の呼び出しで、迷惑な "ReferenceError: *variable name* is not defined" エラーが返されます — これは `output()` 呼び出しと、出力しようとしている変数が同じ関数のスコープにない、つまりこれらの関数呼び出しからは変数が参照できない状態だからです。

**メモ:** 同じスコープルールはループ (`for() { ... }` など) と条件ブロック (`if() { ... }`など) には適用されません。それらは非常によく似ていますが、同じものではありません。混乱しないように注意してください。

**メモ:** ReferenceError: "x" is not defined というエラーは、あなたが遭遇する最も一般的なエラーの 1 つです。このエラーが発生し、問題の変数が定義されていると確信できる場合は、変数のスコープを確認してください。

### 関数の中の関数

別の関数内であっても、どこからでも関数を呼び出すことができます。これは、コードをきれいにする方法としてよく使われます。大きな複雑な関数がある場合は、いくつかのサブ関数に分解すれば分かります。

```js
function myBigFunction() {
  let myValue;

  subFunction1();
  subFunction2();
  subFunction3();
}

function subFunction1() {
  console.log(myValue);
}

function subFunction2() {
  console.log(myValue);
}

function subFunction3() {
  console.log(myValue);
}
```

関数内で使用されている値が適切にスコープ内にあることを確認してください。上記の例では `ReferenceError: myValue is not defined` というエラーが発生します。`myValue`変数は関数呼び出しと同じスコープで定義されていますが、関数定義内では定義されていないためです。従って実際のコードは関数が呼び出されたときに実行されます。これを動くようにするには、次のように関数に値を渡す必要があります。

```js
function myBigFunction() {
  let myValue = 1;

  subFunction1(myValue);
  subFunction2(myValue);
  subFunction3(myValue);
}

function subFunction1(value) {
  console.log(value);
}

function subFunction2(value) {
  console.log(value);
}

function subFunction3(value) {
  console.log(value);
}
```

スキルをテストしよう!
-----------

この記事の最後に来ましたが、最も大事な情報を覚えていますか？次に移る前に、この情報を保持しているか検証するテストがあります — Test your skills: Functions (en-US) を見てください。このテストは次の 2 つの記事でカバーしているスキルを求めていますので、テストの前にそちらを読むほうが良いかもしれません。

まとめ
---

この記事では関数の背後にある基本的な概念を探り、次に実用的な方法を習得し、独自のカスタム関数を構築する手順を紹介しました。

関連情報
----

* 関数の詳細ガイド — ここに含まれていないいくつかの高度な機能について説明します。
* 関数
* デフォルト引数, アロー関数 — 高度な概念リファレンス

* 前のページ
* Overview: Building blocks
* 次のページ


関数の戻り値 - ウェブ開発を学ぶ

関数の戻り値
======

* 前のページ
* Overview: Building blocks
* 次のページ

このコースでの関数の学習を終えるために、最後に議論しておくべき関数についての大事なコンセプトがあります。それは戻り値です。関数によっては意味のある値を返さないものもありますが、値を返すものも当然あります。それらの値が何であるか、あなたのコードの中でどのように利用するのか、またどのように関数に意味のある値を返させるのかについて理解することは重要です。これらについてすべてを以下で紹介します。

| 前提条件: | 基本的なコンピューターリテラシー、基本的な HTML と CSS の知識、JavaScript 初級レベルの知識、関数の知識 |
| --- | --- |
| 目的: | 関数の戻り値とその使い方を理解すること |

戻り値とは？
------

**戻り値**は、その名が示すとおり関数の実行が完了した時に返される値です。戻り値についてそこまで意識してこなかったかもしれませんが、これまでに何度も戻り値を見てきているはずです。

以下の見覚えのある例を見てみましょう (このシリーズの過去の記事より) 。

```js
let myText = "I am a string";
let newString = myText.replace("string", "sausage");
console.log(newString);
// 文字列の replace() 関数は文字列を受け取り、
// 一方の部分文字列をもう一方の部分文字列に置き換え、
// 置き換えられた新しい文字列を返します。
```

`replace()` 関数が `myText` という文字列の上で実行され、2 つの引数が渡されています:

1. 置換される部分文字列 ('string')。
2. 置換する部分文字列 ('sausage')。

この関数が完了 (実行が終了) した時に、関数は置換された新しい文字列を値として返します。上記のコードでは、この戻り値を `newString` 変数に代入しています。

`replace()` 関数についての MDN のリファレンスページには、戻り値 というセクションがあります。関数によって返される値が何か知り把握することはとても大事です。従って、可能な限りこちらも見るようにしてください。

関数によっては何も値を返しません (この場合、リファレンスページでは戻り値を `void` または `undefined` として記載しています)。たとえば、前の記事で作った displayMessage() 関数では、関数が実行されたときに特定の値は返されていません。ただスクリーンのどこかにボックスの表示を作っているだけです。

一般的に、戻り値は関数がある種の計算をしている途中の段階で使用されます。 関数で計算する必要があるいくつかの値を含む最終結果を取得したいとします。関数は値を計算した後、結果を返すことができるため、変数に格納できます。この変数は、計算の次の段階で使用できます。

### オリジナル関数での戻り値の使い方

 カスタム関数から値を返すために、必要なことは、return というキーワードを使うことです。直近の random-canvas-circles.html の例でこれを見たでしょう。`draw()` 関数は 100 のランダムな円を HTML 内に表示します。
 `<canvas>`:

```js
function draw() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
    ctx.fill();
  }
}
```

ループの繰り返しの中で、現在の円の *x 座標*、*y 座標*、*半径*それぞれのランダムな値を生成するために `random()` 関数に対して 3 回の呼び出しが行われます。`random()` 関数はひとつの引数 (整数) を受け取り、`0` からその受け取った数値までの乱数を返します。以下のようになります。

```js
function random(number) {
  return Math.floor(Math.random() \* number);
}
```

次のように書くことも可能です。

```js
function random(number) {
  const result = Math.floor(Math.random() \* number);
  return result;
}
```

しかし最初のものの方がよりコンパクトで、効率よく書けています。

関数が呼び出されるたびに、`Math.floor(Math.random() * number)` の計算の結果が返されます。この戻り値は、関数が呼び出された場所に現れて、コードが続行されます。

したがって、以下を実行すると:

```js
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 \* Math.PI);
```

この時、3 つの `random()` がそれぞれ `500`、`200`、`35` と値を返した場合、このコードは実際には次のように実行されたことになります。

```js
ctx.arc(500, 200, 35, 0, 2 \* Math.PI);
```

コード上の関数の呼び出しがまず行われ、その戻り値が関数の呼び出しの代わりとなり、その後にコードそのものが実行されます。

実践: 戻り値を返す関数を作る
---------------

戻り値を返すオリジナルな関数を書いてみましょう。

1. まず最初に GitHub から function-library.html ファイルをローカル環境にコピーします。このファイルはシンプルな HTML のページで、文字列入力用の `<input>` フィールドとパラグラフ（段落）要素を含んでいます。また、`<script>` 要素があり、この中でページ内の HTML 要素の参照を 2 つの変数で保持させています。このページに対して、テキストボックスに数値を入力したら、入力した数値と関連のある異なる数値を下のパラグラフ要素に表示させるようにしていきます。
2. いくつかの関数を `<script>` 要素に追加していきましょう。既に記述されている 2 行の JavaScript のコードの下に、以下の関数定義を追加します。

```js
function squared(num) {
  return num \* num;
}

function cubed(num) {
  return num \* num \* num;
}

function factorial(num) {
  if (num < 0) return undefined;
  if (num == 0) return 1;
  let x = num - 1;
  while (x > 1) {
    num \*= x;
    x--;
  }
  return num;
}
```

`squared()` 関数と `cubed()` 関数は大変わかりやすいでしょう。引数として渡された値の 2 乗や 3 乗を返しています。`factorial()` 関数は渡された数の階乗を返しています。
3. 次に input に入力された数値を出力する処理を追加していきます。イベントハンドラーを既存の関数の下に記述しましょう。

```js
input.onchange = function () {
  const num = input.value;
  if (isNaN(num)) {
    para.textContent = "You need to enter a number!";
  } else {
    para.textContent =
      num +
      " squared is " +
      squared(num) +
      ". " +
      num +
      " cubed is " +
      cubed(num) +
      ". " +
      num +
      " factorial is " +
      factorial(num) +
      ".";
  }
};
```

ここでは `onchange` イベントハンドラーを作っています。これは文字列入力での `change` イベントが発火した時に実行されます。つまり新しい値が `input` に入力され、送信された時です (たとえば値を入力し、`Tab` か `Return` を押して入力からフォーカスを外す時)。この無名関数が実行されると、`input` に入力された値が `num` 定数に代入されます。
 次に、条件付きテストを行うようにします。もし入力された値が数値でなければ、パラグラフ要素にエラーメッセージを出力します。テストでは、式 `isNaN(num)` が true を返すかどうか見るようにします。一般的に値が数値でないかをテストする際には `isNaN()` 関数を使います。この関数では、渡された値が数値でなければ `true` を返し、数値であれば `false` を返します。
 もしテストが `false` を返した場合、`num` の値は数値です。したがって、数値の 2 乗、3 乗、階乗の値を示す文が、パラグラフ要素内に出力されます。その出力する文章内で必要とする値を計算するために `squared()` 関数、`cubed()` 関数、`factorial()` 関数を呼んでいます。
4. コードを保存して、それをブラウザーで表示してみましょう。

**メモ:** もしサンプルがうまく動作しない場合は、GitHub 上の完成版と比較などしてみてください（実際に動かして確認もできます）。またはお問い合わせください。

あなたの番です!
--------

この時点で、独自の関数をいくつか書き出してライブラリに追加してみましょう。数値の平方根や立方根はどうですか？また、特定の半径を持つ円の円周はどうでしょうか？

関数に関する追加のヒント:

* 関数の中に*エラーハンドリング*を書く別の例を見てみましょう。一般に、必要な引数が検証されていること、および省略可能な引数に何らかのデフォルト値が渡されていることをチェックすることは良い考え方です。このようにしてプログラムがエラーを投げることを減らせます。
* *関数のライブラリ*を作るアイデアについて考えてみてください。プログラミングのキャリアを積んでいくと、何度も同じ類のことを繰り返し行うことになるでしょう。このようなことに対処するために、自分独自のユーティリティ関数のライブラリを作成することは良いアイデアです。新しいコードにコピーしたり、必要に応じて HTML ページにそれを適用したりすることができます。
スキルをテストしよう!
-----------

この記事の最後まで到達しましたが、最も大事な情報を覚えていますか？移動する前に、この情報を維持しているか検証するテストを見ることができます— Test your skills: Functions (en-US) を見てください。

まとめ
---

以上、関数は楽しく、非常に便利で、構文や機能についてまだまだ話すことはたくさんありますが、それらはかなり理解しやすいものです。

もし何か理解できなかったことがありましたら、何度もこの記事を読み込むか、またはお問い合わせください。

関連情報
----

* 関数 — より高度な関数に関連した情報を網羅した詳細なガイド。
* Callback functions in JavaScript — 一般的な JavaScript のパターンは、ある関数を別の関数に*引数として*渡すことです。それは受け取った関数の中で呼び出されます。これについては、このコースの範疇を少し超えていますが、すぐにでも勉強する価値はあります。
* 前のページ
* Overview: Building blocks
* 次のページ


ループするコード - ウェブ開発を学ぶ

ループするコード
========

* 前のページ
* Overview: Building blocks
* 次のページ

プログラミング言語は、繰り返し実行するタスクを素早く終わらせるのがとても得意です。基本的な計算処理から、同じような作業がたくさんあるのならどんな状況でもこなします。今度は JavaScript でそういった目的を果たすために使用するループ構造を見てみましょう。

|  |  |
| --- | --- |
| 前提条件: |
 基本的なコンピューターの知識、HTML と CSS への理解、
 JavaScript の第一歩 |
| 目標: | JavaScript でのループの使い方を理解する。 |

なぜループが有用か
---------

ループは、同じことを何度も何度も繰り返すものです。多くの場合、コードはループを一巡するたびに少しずつ異なり、また、同じコードを実行しても変数が異なることもあります。

### ループコードの例

例えば、`<canvas>` 要素に 100 個のランダムな円を描画したいとします（[更新] ボタンを押すと、例を何度も実行して異なるランダムコレクションを見ることができます）。
```

<button>更新</button> <canvas></canvas>
```

```
html {
  width: 100%;
  height: inherit;
  background: #ddd;
}

canvas {
  display: block;
}

body {
  margin: 0;
}

button {
  position: absolute;
  top: 5px;
  left: 5px;
}
```

こちらはこの例を実装している JavaScript コードです。

```js
const btn = document.querySelector("button");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

document.addEventListener("DOMContentLoaded", () => {
  canvas.width = document.documentElement.clientWidth;
  canvas.height = document.documentElement.clientHeight;
});

function random(number) {
  return Math.floor(Math.random() \* number);
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (let i = 0; i < 100; i++) {
    ctx.beginPath();
    ctx.fillStyle = "rgba(255,0,0,0.5)";
    ctx.arc(
      random(canvas.width),
      random(canvas.height),
      random(50),
      0,
      2 \* Math.PI,
    );
    ctx.fill();
  }
}

btn.addEventListener("click", draw);
```

### ループありとループなし

これですべてのコードを理解する必要はありませんが、実際に 100 個の円を描画している部分を見てみましょう。

```js
for (let i = 0; i < 100; i++) {
  ctx.beginPath();
  ctx.fillStyle = "rgba(255,0,0,0.5)";
  ctx.arc(
    random(canvas.width),
    random(canvas.height),
    random(50),
    0,
    2 \* Math.PI,
  );
  ctx.fill();
}
```

* `random(x)` は、コードの手前で定義されており、 `0` と `x-1` の間の実数を返します。

 基本的なことが分かると思います。ループを使用してこのコードを 100 回反復処理し、それぞれがページ上のランダムな位置に円を描画します。
 必要なコードの量は、100 個の円を描画する場合でも、1000 個の円を描画する場合でも、1 万個の円を描画する場合でも同じです。
 変更しなければならないのは、たった一つの数字だけです。

もしここでループを使用していなければ、描画したい円ごとに以下のコードを繰り返して書く必要があります。

```js
ctx.beginPath();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.arc(
  random(canvas.width),
  random(canvas.height),
  random(50),
  0,
  2 \* Math.PI,
);
ctx.fill();
```

これはとても退屈で、メンテナンスも大変でしょう。

コレクション内のループ処理
-------------

ループを使用する場合のほとんどは、アイテムのコレクションがあって、すべてのアイテムに対して何かを行いたいときです。

`Array` は、コレクションの一種です。このコースの配列の章で紹介しました。
 しかし、JavaScript には他にも `Set` や `Map` などのコレクションがあります。

### for...of ループ

コレクションをループ処理する基本的なツールは `for...of` ループです。

```js
const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (const cat of cats) {
  console.log(cat);
}
```

この例では、`for (const cat of cats)` は次のように言っています。

1. コレクション `cats` が指定されたら、コレクション内の最初のアイテムを取得する。
2. それを変数 `cat` に割り当てて、中括弧 `{}` で囲まれたコードを実行する。
3. 次のアイテムを取得し、コレクションの終わりに達するまで (2) を繰り返す。
### map() と filter()

JavaScript には、コレクションに対してより特化したループもあるので、ここではそのうちの 2つを紹介します。

`map()` を使用すると、コレクション内の各アイテムに対して何かを行い、変更されたアイテムを格納した新しいコレクションを作成することができます。

```js
function toUpper(string) {
  return string.toUpperCase();
}

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const upperCats = cats.map(toUpper);

console.log(upperCats);
// [ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ]
```

ここでは、`cats.map()` に関数を渡すと、`map()` は配列内のそれぞれのアイテムにその関数を 1 回ずつ、そのアイテムを渡して呼び出します。そして、それぞれの関数呼び出しの返値を新しい配列に追加し、最後に新しい配列を返します。この場合、提供した関数はアイテムを大文字に変換するので、結果として得られる配列には、すべてのネコ科動物がが大文字で格納されます。
```

[ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ]
```

`filter()` を使用すると、コレクション内のそれぞれのアイテムをテストし、一致するアイテムのみを格納した新しいコレクションを作成することができます。

```js
function lCat(cat) {
  return cat.startsWith("L");
}

const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const filtered = cats.filter(lCat);

console.log(filtered);
// [ "Leopard", "Lion" ]
```

 これは `map()` とよく似ていますが、渡す関数が論理値を返す点が異なります。 もし `true` を返すなら、アイテムは新しい配列に含まれます。
 この関数では、アイテムが文字「L」で始まるかどうかをテストするので、結果は名前が「L」で始まる猫だけを含む配列になります。
```

[ "Leopard", "Lion" ]
```

 なお、`map()` と `filter()` は、どちらもよく関数式と一緒に使われます。これは関数モジュールで学びます。
 関数式を使用すると、上の例をもっとコンパクトに書き直すことができます。

```js
const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

const filtered = cats.filter((cat) => cat.startsWith("L"));
console.log(filtered);
// [ "Leopard", "Lion" ]
```

標準的な for ループ
------------

 上の「円を描く」例では、ループさせるアイテムのコレクションがある訳ではありません。実際には、同じコードを 100 回実行したいだけです。
 このような用途では、`for` ループを使用する必要があります。
 これは以下のような構文があります。構文は以下の通りです。
```

for (初期化処理; 条件; 最後の式) {
  // 実行するコード
}
```

ここでは、次のようになります。

1. `for` キーワードに続き括弧があります。
2. 括弧の中には、セミコロンで区切られた以下の項目があります。
    1. **初期化処理**: これはたいていの場合、繰り返し回数分増やしていく変数の初期化処理となります。
     この変数を**カウンター変数**と呼ぶことがあります。
    2. **条件**: これは、ループがいつ繰り返しをやめるかを定義します。
     これはふつう、比較演算子を伴って、終了条件に達したかどうかを確認します。
    3. **最後の式**: これはループの 1 回が終了する度に評価される（または実行される）コードです。
     通常、カウンター変数を増加させ（場合によっては減少させ）、条件が `true` ではなくなるポイントに近づけていきます。
3. コードのブロックを格納する中括弧。このコードは、ループが反復処理されるたびに実行されます。
### 平方の計算

実際の例を見て、これらの機能をより明確にイメージできるようにしましょう。
```

<button id="calculate">計算</button>
<button id="clear">クリア</button>
<pre id="results"></pre>
```

```js
const results = document.querySelector("#results");

function calculate() {
  for (let i = 1; i < 10; i++) {
    const newResult = `${i} x ${i} = ${i \* i}`;
    results.textContent += `${newResult}\n`;
  }
  results.textContent += "\n完了!";
}

const calculateBtn = document.querySelector("#calculate");
const clearBtn = document.querySelector("#clear");

calculateBtn.addEventListener("click", calculate);
clearBtn.addEventListener("click", () => (results.textContent = ""));
```

これは次のような出力結果となります。

このコードは、1 から 9 までの数字の平方を計算し、その結果を書き出します。コードの中心は、計算を行う `for` ループです。

`for (let i = 1; i < 10; i++)` の行を 3 つの部分に分割してみましょう。

1. `let i = 1`: カウンター変数である `i` は `1` から始めます。ループを一周するたびにカウンターに代入するため、カウンターに `let` を使用しなければならないことに注意してください。
2. `i < 10`: `i` が `10` よりも小さい限り、ループを繰り返し続けます。
3. `i++`: ループを一周するたびに `i` に 1 を加算します。

ループの内部では、現在の `i` の値の平方、すなわち `i * i` を計算します。計算した内容と結果を表す文字列を作成し、出力テキストに追加します。また、次に追加した文字列が改行されるように、`\n` も追加しています。すなわち、

1. 最初の実行時は `i = 1` なので `1 x 1 = 1` を追加します。
2. 二番目の実行時は `i = 2` なので `2 x 2 = 4` を追加します。
3. 以下、同様に行います。
4. `i` が `10` と等しくなったら、ループの実行を停止して、ループの下の次のコードにまっすぐ移動し、`完了!` というメッセージを新しい行に出力します。
### for ループでコレクションを繰り返し処理

`for` ループの代わりに、`for...of` ループを使用してコレクションを反復処理することができます。

上の `for...of` の例をもう一度見てみましょう。

```js
const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (const cat of cats) {
  console.log(cat);
}
```

このコードは次のように書き換えることができます。

```js
const cats = ["Leopard", "Serval", "Jaguar", "Tiger", "Caracal", "Lion"];

for (let i = 0; i < cats.length; i++) {
  console.log(cats[i]);
}
```

 このループでは、`i` を `0` で開始し、`i` が配列の長さに達した時点で停止しています。
 そして、ループの中で `i` を使って、配列のそれぞれのアイテムに順番にアクセスしています。

 JavaScript の初期のバージョンでは、`for...of` は存在しなかったので、これが配列を反復処理する標準的な方法でした。
 しかし、この方法は、コードにバグを引き起こす可能性が高くなります。例えば、

* 配列の添字が 1 ではなく 0 から始まることを忘れて、`i` を `1` から始めてしまうかもしれません。
* 最後の配列の添字が `length - 1` にあることを忘れて、`i <= cats.length` で止めてしまうかもしれません。

このような理由から、通常は、できる限り `for...of` を使用するのがベストです。

 時には、配列を繰り返し処理するために `for` ループを使用する必要があります。
 例えば、以下のコードでは、猫の一覧をメッセージとして出力したい。

```js
const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

for (const cat of cats) {
  myFavoriteCats += `${cat}, `;
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, Jasmine, "
```

最終的に出力される文章はあまり整ったものではありません。
```

My cats are called Pete, Biggles, Jasmine,
```

最後の猫については、このように別の処理をしてくれるのが望ましいと思います。
```

My cats are called Pete, Biggles, and Jasmine.
```

しかし、これを行うには、ループがいつ最後の反復処理に入ったかを知る必要があります。そのためには、`for` ループを使い、`i` の値を調べればよいのです。

```js
const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

for (let i = 0; i < cats.length; i++) {
  if (i === cats.length - 1) {
    // 配列の最後にいる場合
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."
```

break でループを終了
-------------

 すべての反復処理が終了する前にループを終了したいときは、break 文を使用して終了させることができます。
 前回の記事の switch 文で、入力した値が switch 文の case に一致したとき、switch 文を抜け、それ以降のコードを実行するために `break` 文を使用しました。

これはループでも同様で、`break` 文を使用することで即時にループを抜けて、ブラウザーに続きのコードを実行させることができます。

 連絡先や電話番号の配列を検索して、見つけたい番号だけを返したいとします。
 まずは HTML です。検索するテキスト入力用の `<input>` 要素と、検索内容を送信 (submit) する `<button>` 要素、検索結果を表示する `<p>` 要素を備えます。

```html
<label for="search">連絡先の名前: </label>
<input id="search" type="text" />
<button>検索</button>

<p></p>
```

現在の JavaScript では、

```js
const contacts = [
  "クリス:2232322",
  "サラ:3453456",
  "ビル:7654322",
  "メアリー:9998769",
  "ダイアン:9384975",
];
const para = document.querySelector("p");
const input = document.querySelector("input");
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  const searchName = input.value.toLowerCase();
  input.value = "";
  input.focus();
  para.textContent = "";
  for (const contact of contacts) {
    const splitContact = contact.split(":");
    if (splitContact[0].toLowerCase() === searchName) {
      para.textContent = `${splitContact[0]}の電話番号は${splitContact[1]}です。`;
      break;
    }
  }
  if (para.textContent === "") {
    para.textContent = "連絡先が見つかりません。";
  }
});
```

1. コードの先頭で、いくつか変数を宣言しています。その中に、連絡先の情報を持った配列があり、各要素は名前と電話番号をコロンで区切った文字列となっています。
2. 次に、ボタン (`btn`) にイベントリスナーを設定しています。ボタンが押されたときに検索結果が戻ってくるようになっています。
3. テキスト入力欄に入力された値を `searchName` という変数に格納してから、次の検索に備え、入力欄をクリアし、フォーカスを設定しています。検索に大文字小文字を区別しないよう、文字列に `toLowerCase()` を実行しているのに注意してください。
4. ここからが本題の `for...of` ループです。
    1. ループの中では、まず現在の連絡先をコロン文字で分割し、結果の 2 つの値を `splitContact` という配列に格納します。
    2. それから、条件文を用いて、`splitContact[0]` （連絡先の名前）が入力された `searchName` にまた `toLowerCase()` を使って小文字化したものと等しいかを判定します。
     もし等しければ、文字列を段落に入れてその連絡先の電話番号を示し、`break` を使用してループを終了しています。
5. ループの後、連絡先が設定されたかどうかをチェックし、設定されていない場合は段落テキストを「連絡先が見つかりません。」に設定しています。

**メモ:** すべてのソースは GitHub で見ることができます（動いているデモもあります）。

continue で繰り返しをスキップする
---------------------

continue 文は `break` と同じような動作をします。けれど、ループを完全に抜けてしまうのではなく、次の繰り返しまで飛ばします。
 それでは、今度は入力として数値を受け取り、その数以下で整数の平方である値のみを返すという例を見てみましょう。

HTML は基本的に前回の例と同じで、単純なテキスト入力と、出力用の段落があります。

```html
<label for="number">数値を入力してください: </label>
<input id="number" type="text" />
<button>整数の平方を生成</button>

<p>出力:</p>
```

JavaScript もほとんど同じですが、ループ自体が若干異なります。

```js
const para = document.querySelector("p");
const input = document.querySelector("input");
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  para.textContent = "出力: ";
  const num = input.value;
  input.value = "";
  input.focus();
  for (let i = 1; i <= num; i++) {
    let sqRoot = Math.sqrt(i);
    if (Math.floor(sqRoot) !== sqRoot) {
      continue;
    }
    para.textContent += `${i} `;
  }
});
```

出力結果はこちらです。

1. 今回の入力内容は数値 (`num`) です。`for` ループには、カウンターの初期値として、（今回は 0 ではなく）1 が与えられ、終了する条件としてカウンターが入力値 (`num`) より大きくなった場合と指定されており、イテレーターとして、カウンターに 1 ずつ加算するよう指定されています。
2. ループ内部では、各値の平方根を Math.sqrt(i) を使用して求め、求めた平方根を切り捨てた値が、切り捨てる前の平方根と等しいかどうかを調べています（切り捨てには Math.floor() に任意の数値を渡します）。
3. もし、平方根と切り捨てた数値が等しくないのなら (`!==`)、平方根は整数ではないことを示しています。整数以外には興味がありませんので、`continue` 文を用いて、その数値をどこにも保持することなく、次のループの繰り返しまでスキップします。
4. もし、その平方根が整数値であるならば、if ブロックは飛ばされるので、`continue` 文は実行されません。代わりに、現在の `i` の値を段落の内容の後ろにスペースと一緒に結合します。

**メモ:** すべてのソースは GitHub でも見ることができます（動いているデモもあります）。

while と do...while
------------------

`for` は JavaScript で利用可能な唯一のループの種類ではありません。実際には多くのものがありますが、これらのすべてを理解する必要はありませんが、仕事の同じ機能をわずかに異なる方法で認識できるように、他のものの構造を見ておく価値があります。

まず、while ループを見てみましょう。このループの構文は次のようになります。
```

初期化処理
while (条件) {
  // 実行するコード

  最後の式
}
```

 これは `for` ループととてもよく似た動作をしますが、初期化変数がループの前に設定される点と、最後の式が、これら 2 つの項目が括弧の中に入っているのではなく、実行するコードの後にループの中に含まれている点が異なります。
 条件は括弧の中に入っており、その前には `for` ではなく `while` キーワードが置かれています。

 同じ 3 つの項目が、for ループの中で定義されているのと同じ順番で存在しています。
 これは、条件が真かどうかをチェックする前に、初期化処理を定義しておく必要があるためです。
 そして、ループ内のコードが実行された（反復処理が完了した）後に最後の式が実行されますが、これは条件がまだ真である場合にのみ実行されます。

猫のリストの例をもう一度見てみましょう。ただし、while ループを使うように書き直してみましょう。

```js
const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

let i = 0;

while (i < cats.length) {
  if (i === cats.length - 1) {
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }

  i++;
}

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."
```

**メモ:** これは期待どおりに動作します。GitHub でライブ実行してみてください（完全なソースコードを見ることもできます）。

do...while ループはとてもよく似ていますが、while 構造の別な形です。
```

初期化処理
do {
  // 実行するコード

  最後の式
} while (条件)
```

この場合、初期化処理は再び、ループが始まる前に来ています。キーワードは、実行するコードと最期の式を含む中括弧の直前にあります。

`do...while` ループと `while` ループの主な違いは、*`do...while` ループの中のコードは常に少なくとも 1 回は実行される* ということです。それは、ループ内のコードの後に条件が来るからです。つまり、常にそのコードを実行し、その後、もう一度実行する必要があるかどうかをチェックするのです。`while` ループや `for` ループでは、チェックが最初に来るので、そのコードは一度も実行されないかもしれません。

`do...while` ループを使用するように、猫のリストの例をもう一度書き直してみましょう。

```js
const cats = ["Pete", "Biggles", "Jasmine"];

let myFavoriteCats = "My cats are called ";

let i = 0;

do {
  if (i === cats.length - 1) {
    myFavoriteCats += `and ${cats[i]}.`;
  } else {
    myFavoriteCats += `${cats[i]}, `;
  }

  i++;
} while (i < cats.length);

console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmine."
```

**メモ:** こちらも、これは期待どおりに動作します。GitHub でライブ実行してみてください（完全なソースコードを見ることもできます）。

**警告:** while と do...while では、すべてのループと同様に、カウンター変数を増加、もしくは場合により減少させて、最終的に条件が false となるようにする必要があります。
 そうしなければループは永遠に進み、ブラウザーはそれ強制的に停止させるか、クラッシュします。これは**無限ループ**と呼ばれます。

アクティブラーニング: 発射のカウントダウン
----------------------

 この練習では、出力ボックスへの簡単な発射のカウントダウンを 10 から Blast off まで表示してください。
 具体的には、次のようなことをしていただきます。

* 10 から 0 までのループ。初期化処理として `let i = 10;` を示します。
* それぞれの反復処理に対して、新しい段落を作成し、それを出力用の `<div>` に追加します。`const output = document.querySelector('.output');` を使うことを選択しました。
 コメント内で、ループ内のどこかで使用する必要がある 3 つのコード行を提供します。
    + `const para = document.createElement('p');` — 新しい段落を作成します。
    + `output.appendChild(para);` — 出力の `<div>` に段落を追加します。
    + `para.textContent =` — 段落内のテキストを、イコール記号の後の右辺においたものにします。
* 反復回数が異なれば、その反復回数の段落に入れるテキストも異なります（条件文と複数の `para.textContent =` 行が必要です）。
    + 数字が 10 の場合、段落に "Countdown 10" と出力する。
    + 数字が 0 の場合、段落に "Blast off!" と出力する。
    + その他の数字では、段落にその数字を出力する。
* イテレーターを含めることを忘れないでください！ですが、この例では各反復の後にカウント（アップではなく）ダウンするため、`i++` は要らないでしょう。減少方向にどうやって反復するのでしょうか？

**メモ:** あなたがループ（例えば while(i>=0)）からタイピングを始めると、ブラウザーが固まってしまうかもしれません。終了条件をまだ入力していないからです。注意して下さい。この問題に対処するにはコメントの中にコードを書き始めて、完了してからコメントを削除することです。

間違えた場合は、［リセット］ボタンを使用してこの例をいつでもリセットできます。あなたが本当に立ち往生したら、［解答を表示］を押して解決策を見てください。
```

<h2>ライブ出力</h2>
<div class="output" style="height: 410px;overflow: auto;"></div>

<h2>編集可能なコード</h2>
<p class="a11y-label">
  Esc を押すと、コード領域からフォーカスを外すことができます（Tab
  はタブ文字を挿入します）。
</p>
<textarea id="code" class="playable-code" style="height: 300px;width: 95%">
let output = document.querySelector('.output');
output.innerHTML = '';

// let i = 10;

// const para = document.createElement('p');
// para.textContent = ;
// output.appendChild(para);
</textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="リセット" />
  <input id="solution" type="button" value="解答を表示" />
</div>
```

```css
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "解答を表示";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "解答を表示") {
    textarea.value = solutionEntry;
    solution.value = "解答を隠す";
  } else {
    textarea.value = userEntry;
    solution.value = "解答を表示";
  }
  updateCode();
});

let jsSolution = `const output = document.querySelector('.output');
output.innerHTML = '';

let i = 10;

while (i >= 0) {
 const para = document.createElement('p');
 if (i === 10) {
 para.textContent = \`Countdown \${i}\`;
 } else if (i === 0) {
 para.textContent = 'Blast off!';
 } else {
 para.textContent = i;
 }

 output.appendChild(para);

 i--;
}`;

let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  let caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );

  textarea.value = front + text + back;
  caretPos += text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = () => {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "解答を表示") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

アクティブラーニング: ゲストリストに記入する
-----------------------

この演習では、配列に格納された名前のリストを、ゲストリストにしていただきます。しかし、フィルとローラは貪欲で無礼で、いつも料理を全部食べてしまうので、ゲストに入れたくありません！私たちは 2 つのリストを用意しました。1 つはゲストを認めるためのリスト、もう 1 つはゲストを拒否するためのリストです。

具体的には、次のようなことをしていただきます。

* 0 から `people` 配列の長さまで反復するループを作成します。
* 各ループ反復中に、条件文を使用して現在の配列項目が "Phil" または "Lola" に等しいかチェックします。
    + そうである場合は、`refused` 段落の `textContent` の最後に配列項目を連結し、その後にカンマとスペースを続けます
    + そうでない場合は、配列項目を、`admitted` 段落の `textContent` の末尾に連結し、その後にカンマとスペースを続けます

既に提供されているものは次のものです。

* `refused.textContent +=` — `refused.textContent` の後に文字を連結する開始行
* `admitted.textContent +=` — `admitted.textContent` の後に文字を連結する開始行

 特別ボーナス問題 — 上のタスクを正常に完了すると、カンマで区切られた 2 つの名前リストが残されますが、それらは整頓されません。それぞれの末尾にカンマがあります。
 それぞれの場合に最後のカンマを切り取り、末尾にピリオドを追加した行をどのように書くかという問題を解決出来ますか？
 ヘルプのため便利な文字列メソッドの記事を見てみてください。

間違えた場合は、「リセット」ボタンを使用してこの例をいつでもリセットできます。あなたが本当に立ち往生したら、"ソリューションを表示"を押して解決策を見てください。
```

<h2>ライブ出力</h2>
<div class="output" style="height: 100px;overflow: auto;">
  <p class="admitted">Admit: </p>
  <p class="refused">Refuse: </p>
</div>

<h2>編集可能なコード</h2>
<p class="a11y-label">
  Esc を押すと、コード領域からフォーカスを外すことができます（Tab はタブ文字を挿入します）。
</p>
<textarea id="code" class="playable-code" style="height: 400px;width: 95%">
const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce'];

const admitted = document.querySelector('.admitted');
const refused = document.querySelector('.refused');
admitted.textContent = 'Admit: ';
refused.textContent = 'Refuse: ';

// loop starts here

// refused.textContent += ;
// admitted.textContent += ;

</textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="リセット" />
  <input id="solution" type="button" value="解答を表示"
</div>
```

```
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "解答を表示";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "解答を表示") {
    textarea.value = solutionEntry;
    solution.value = "解答を隠す";
  } else {
    textarea.value = userEntry;
    solution.value = "解答を表示";
  }
  updateCode();
});

const jsSolution = `
const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce'];

const admitted = document.querySelector('.admitted');
const refused = document.querySelector('.refused');

admitted.textContent = 'Admit: ';
refused.textContent = 'Refuse: ';

for (const person of people) {
 if (person === 'Phil' || person === 'Lola') {
 refused.textContent += \`\${person}, \`;
 } else {
 admitted.textContent += \`\${person}, \`;
 }
}

refused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + '.';
admitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + '.';`;

let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  let caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );

  textarea.value = front + text + back;
  caretPos += text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = () => {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "解答を表示") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

どの種類のループを使用するのか
---------------

配列やそれを扱うオブジェクトを反復処理し、各項目の添字の位置にアクセスする必要がない場合は、`for...of`が最良の選択となります。読みやすいし、間違うことも少ないからです。

 その他の用途では、`for`、`while`、`do...while` のループはほとんど互換性があります。
 これらはすべて同じ問題を解決するために使うことができ、どれを使うかは個人的な好み、つまり覚えやすいか直感的かによって大きく変わってきます。
 少なくとも最初は `for` をお勧めします。初期化処理、条件、最後の式がすべて括弧の中にきちんと入るので、どこに何があるのかがわかりやすく、見落としがないかをチェックしやすいからです。

では、もう一度見てみましょう。

まずは `for...of` です。
```

for (const 項目 of 配列) {
  // 実行するコード
}
```

`for` です。
```

for (初期化処理; 条件; 最後の式) {
  // 実行するコード
}
```

`while` です。
```

初期化処理
while (条件) {
  // 実行するコード

  最後の式
}
```

そして最後は `do...while` です。
```

初期化処理
do {
  // 実行するコード

  最後の式
} while (条件)
```

**メモ:** 高度な/特殊な状況やこの記事の範囲を超えて有用な、他のループタイプ/機能もあります。ループ学習をさらに進めたい場合は、高度なループと反復処理ガイドをお読みください。

スキルテスト
------

この記事の最後に達しましたが、最も大切な情報を覚えていますか？次に進む前に、この情報が身に付いたかどうかを確認するテストがあります。Test your skills: Loops (en-US) を見てください。

まとめ
---

 この記事では、背後にある基本的な概念と、JavaScript でコードをループする際に使用できるさまざまなオプションについて説明しました。
 ループが繰り返しの多いコードを処理するのに適したメカニズムであることを理解し、自分の例でループを使う気になったはずです。

理解できなかったことがあれば、記事をもう一度読んだり、ヘルプを求めて私たちに連絡してください。

関連情報
----

* ループと反復処理
* for...of のリファレンス
* while と do...while リファレンス
* break と continue リファレンス
* What's the Best Way to Write a JavaScript For Loop? — 高度なループのベストプラクティス
* 前のページ
* Overview: Building blocks
* 次のページ


コードでの意思決定 — 条件文 - ウェブ開発を学ぶ

コードでの意思決定 — 条件文
===============

* Overview: Building blocks
* 次のページ

どのプログラミング言語でも、コードは様々な入力に応じた決定を迫られ、その結果として動作を起こします。例えば、ゲームではプレイヤーの残機が 0 になった場合、ゲームオーバーとなります。天気アプリは朝に起動された場合は日の出の画像を表示し、夜に起動された場合は星や月の画像を表示します。この記事では、JavaScript において、条件文と呼ばれるものがどのように動作するかを説明します。

| 前提条件: | 基本的なコンピューターの知識および HTML と CSS への理解、JavaScript の第一歩。 |
| --- | --- |
| 目的: | JavaScript における条件分岐構造をどのように使用するかを理解する。 |

すべては条件次第
--------

人類 (と他の動物たち)は 小さいもの (「クッキーを 1 つ食べるべきか、2 つ食べるべきか...。」) から大きいもの (「故郷に残って親父の農場を継ぐべきか、アメリカで宇宙物理学を学ぶべきか...。」) まで、生活に関わるすべての決定を下します。

JavaScript では、条件文を使ってそのような決定を下すことが可能です。条件文は、選ばなければならない選択肢 (例えば「クッキーを 1 つまたは 2 つ食べる」) からそれを選んだ場合の結果を導き出します (おそらく「1 つクッキーを食べる」を選んだら、「まだちょっとお腹が空いている」という結果となるでしょうし、「2 つクッキーを食べる」を選んだら「お腹いっぱい。だけどクッキーを全部食べてママに怒られる」という結果となってしまうでしょう。)

![](/ja/docs/Learn/JavaScript/Building_blocks/conditionals/cookie-choice-small.png)

if ... else ステートメント
-------------------

それでは、JavaScript で最もよく使われる条件文から始めましょう。それは `if ... else` ステートメントです。

### if ... else の基本的な構文

`if...else` の基本的な構文は以下の擬似コードのようになっています。
```

if (条件式) {
  条件式が true の場合に実行されるコード
} else {
  それ以外の場合に実行されるコード
}
```

ここでは...

1. `if` キーワードの後ろに括弧が並んでいます。
2. 判断に用いる条件式はその括弧の中にあります (たいていの場合は「この値はもう一方より大きい」や、「この値は存在する」などです)。この条件には、前回のモジュールで習った比較演算子を使用し、`true` または `false` を返します。
3. 中にコードが書いてある (実際のコードはどんなものでも構いません) 中括弧のペアは、条件式が `true` の場合に実行されます。
4. 続いて `else` キーワードがあります。
5. さらに他のコードが書いてある (こちらもどんなコードでも構いません) 中括弧のペアは条件式が `true` ではない場合に実行されます。

このコードは (英語を使う人には) とても読みやすいものになっています。このコードは「もし ( **if** ) 条件式 ( **condition** ) が `true` を返したら A のコードを実行し、それ以外ならば ( **else** ) B のコードを実行する」と読めます。

`else` とそれに続く中括弧は必ずしも書く必要がないことを覚えておきましょう。次のコードも全く問題のないコードです。
```

if (条件式) {
  条件式が true の場合に実行されるコード
}

普通に実行されるコード
```

ここで注意しておかなければならないことがあります。それは 2 つ目のコードブロックは、条件分岐の管理下になく、条件式が `true` か `false` かに関係なく、**常に**実行されることです。これはまったく悪いことではないのですが、条件に応じてどちらか一方のみ動かしたいと思っている場合には、気を付けておかないと思った通りの動作をしないでしょう。

最後の確認点として、`if...else` ステートメントが中括弧なしで書かれているのを見ることがあります。以下のような省略した書き方です。
```

if (条件式) 条件式が true の場合に実行されるコード
else それ以外の場合に実行されるコード
```

これは正常なコードですが、あまり推奨されません。中括弧でコードブロックを分割して、複数の行とインデントを使って書いたほうが読みやすく、コードがどうなっているかを把握しやすいためです。

### 実際の例

構文をもっとよく理解するため、実際の例を考えてみましょう。例えば両親にお使いを頼まれた子供を想像してください。「欲しがってたおもちゃがあるよね。お使いを頼まれてくれたら、お小遣いを追加であげるよ。」と親が頼みます。JavaScript では以下のようなコードで表現できます。

```js
let shoppingDone = false;

if (shoppingDone === true) {
  let childsAllowance = 10;
} else {
  let childsAllowance = 5;
}
```

このコードは常に `shoppingDone` 変数が `false` なので、かわいそうな子供は追加のお小遣いを受け取れません。両親が子供がお使いを完了した場合に `shoppingDone` 変数を `true` にセットしてあげるかどうかはプログラム次第です (つまり私たち次第です。)

**メモ:** GitHub で上記のコードの完全なバージョンが公開されています (ライブ実行でも確認できます。)

### else if

先ほどの例では実行結果は 2 つだけでしたが、もっと選択肢がある場合はどうでしょうか？

`else if` を使って、追加の選択肢を `if...else` に繋ぐ方法があります。追加の選択肢は `if() { ... }` と `else { ... }` の間に、コードブロックを続けて追加する必要があります。具体的な例として、天気予報のアプリケーションの一部を見てみましょう。

```html
<label for="weather">今日の天気を選択してください: </label>
<select id="weather">
  <option value="">--選択してください--</option>
  <option value="sunny">晴れ</option>
  <option value="rainy">雨</option>
  <option value="snowing">雪</option>
  <option value="overcast">曇り</option>
</select>

<p></p>
```

```js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  if (choice === "sunny") {
    para.textContent =
      "今日はとてもいい天気です。短いパンツをはいて、砂浜や公園に出かけ、アイスクリームを食べましょう！";
  } else if (choice === "rainy") {
    para.textContent =
      "雨が降っています。レインコートと傘を忘れないようにして、できる限り室内で過ごしましょう。";
  } else if (choice === "snowing") {
    para.textContent =
      "雪が降ってとても寒いです！室内でホットチョコレートを飲むか、雪だるまを作るのがよいでしょう。";
  } else if (choice === "overcast") {
    para.textContent =
      "雨は降っていませんが、空はとても暗くなっています。万が一に備えレインコートを持ちましょう。";
  } else {
    para.textContent = "";
  }
}
```

1. HTML に、天気を選ぶことが可能な `<select>` 要素があり、1 つの段落がありますね。
2. JavaScript では、`<select>` と `<p>` の各要素について、参照を取得して保持し、`<select>` 要素にはイベントリスナーを設定しています。もし、要素の値が変わったら `setWeather()` 関数が動きます。
3. この関数が実行されると、まずは `choice` という変数に、`<select>` 要素の現在選択されている値を入れます。そして、条件文を使い、`choice` の値に応じた文字列が段落に設定されます。最初の `if() {...}` のブロックを除いて、どのように `else if() {...}` のブロックで判定しているか注目してください。
4. 一番下の `else {...}` 選択肢は、「最後の手段」となるオプションで、この中のコードは、どの条件にも一致しなかった場合 (`true` とならなかった場合) に実行されます。今回の場合選択されていない場合に、段落を空にしています。何も選択されていない場合というのは、ユーザーが再度最初に表示されていた「--選択してください--」というオプションを選んだ場合です。

**メモ:** GitHub で上記のコードの完全なバージョンが公開されています (ライブ実行でも確認できます。)

### 比較演算子に関するメモ

比較演算子は条件文の中で使われます。JavaScript での数学入門 — 数値と演算子についてで初めて出てきましたね。演算子には以下のようなものがありました。

* `===` と `!==` は、ある値がもう一方の値と等しいか、もしくは等しくないかを判定します。
* `<` と `>` は、ある値がもう一方の値より大きいか、より小さいかを判定します。
* `<=` と `>=` は、ある値がもう一方の値以上か、以下かを判定します。

**メモ:** もし記憶があいまいならば、上記のリンク先を見て復習しましょう。

真偽 (`true`/`false`) の値を判定する場合には少しの配慮が必要であることを付け加えさせてください。おそらく何度か躓くであろう、よくあるパターンです。`false`、`undefined`、`null`、`0`、`NaN`、空文字列 (`''`) 以外の値は条件文で使った場合に `true` となります。ですから、その値が `true` であるか判定したい場合や、その値が存在するか (例えば、`undefined` ではないこと) 判定したい場合は単に変数名を使用するだけです。

```js
let cheese = "チェダー";

if (cheese) {
  console.log("やった！チーズトーストを作るチーズがあるよ。");
} else {
  console.log("今日はチーズトーストのチーズがないよ。");
}
```

先ほどの子供のお使いの例に戻ると、以下のようにも書くことができます。

```js
let shoppingDone = false;

if (shoppingDone) {
  // '=== true' を明示的に指定する必要はありません
  let childsAllowance = 10;
} else {
  let childsAllowance = 5;
}
```

### 入れ子の if ... else

`if...else` ステートメントを入れ子にして、他の `if...else` ステートメントの中で使用することは全く問題ありません。例えば、天気予報アプリケーションで気温に応じて表示する内容を切り替えたい場合以下のように書くことができます。

```js
if (choice === "sunny") {
  if (temperature < 86) {
    para.textContent =
      "外の気温は " +
      temperature +
      " 度です — とてもいい天気です。海水浴や、公園に出かけてアイスクリームを食べましょう";
  } else if (temperature >= 86) {
    para.textContent =
      "外の気温は " +
      temperature +
      " 度です — かなり暑いです！外出する場合にはアイスクリームを持って出かけましょう。";
  }
}
```

内側の `if...else` ステートメントは、外側の `if` ステートメントとは完全に独立して作用します。

### 論理演算子: AND と OR と NOT

複数の条件を入れ子の `if...else` ステートメントを書かずに判定したいなら、論理演算子の出番です。条件文の中で使用する場合、AND と OR は以下の作用をもたらすでしょう。

* `&&` — AND は 2 つ以上の式を一つに繋げ、それぞれの式を個別に評価して、すべて `true` になった場合、その式全体が `true` として返します。
* `||` — OR は 2 つ以上の式を 1 つに繋げ、それぞれの式を個別に評価し、最初に `true` になったところで、その式全体を `true` として返します。

AND の例を示すため、先ほどのコードを書き直すと以下のようになります。

```js
if (choice === "sunny" && temperature < 86) {
  para.textContent =
    "外の気温は " +
    temperature +
    " 度です — とてもいい天気です。海水浴や、公園に出かけてアイスクリームを食べましょう";
} else if (choice === "sunny" && temperature >= 86) {
  para.textContent =
    "外の気温は " +
    temperature +
    " 度です — かなり暑いです！外出する場合にはアイスクリームを持って出かけましょう。";
}
```

例では、最初のブロックは `choice === 'sunny'` *と* `temperature < 86` のどちらも `true` となった場合にのみ実行されます。

今度は OR の例を見てみましょう。

```js
if (iceCreamCarOutside || houseStatus === "火事") {
  console.log("すぐに家から出ましょう。");
} else {
  console.log("それでは家にいましょう。");
}
```

論理演算子の最後は NOT です。`!` 演算子で表され、式を否定するのに使用します。それでは先ほどの OR と組み合わせてみましょう。

```js
if (!(iceCreamVanOutside || houseStatus === "火事")) {
  console.log("それでは家にいましょう。");
} else {
  console.log("すぐに家から出ましょう。");
}
```

このコード例では、OR ステートメントが `true` となれば、NOT 演算子がそれを否定します。そのため、式全体は `false` となります。

論理ステートメントは思うがままに、いくつでも繋げることが可能です。次の例では両方の OR ステートメントが真を返した場合に AND ステートメントが真となり、`if` の中のコードが実行されます。

```js
if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === "スティーブ")) {
  // コードを実行
}
```

論理 OR 演算子を使用するうえでよくある間違いは、判定しようとしている変数を一度だけ書いて、その後に判定したい値を `||` (OR) 演算子で区切って指定する誤りです。次のような例です。

```js
if (x === 5 || 7 || 10 || 20) {
  // コードを実行する
}
```

この場合、`if(...)` の条件式は常に真となります。なぜなら 7 (もしくはその他 0 以外の数値) が常に `true` と評価されるためです。この条件式は「もし x が 5 であるか 7 が真であるならば (7 は常に真です)」となります。これは求めているものではありませんよね！このコードの誤りを修正するためには、OR 演算子の隣に常に完全な条件を書かなければなりません。

```js
if (x === 5 || x === 7 || x === 10 || x === 20) {
  // コードを実行する
}
```

switch ステートメント
--------------

`if...else` ステートメントは条件の判定を上手くこなしていましたが、欠点がないわけではありません。いくつかの選択肢しかない場合には申し分ないのですが、AND / OR の条件が複雑になるにつれて (例えば、複数の論理演算子を使ったりする場合など)、相当量のコードを書かなければなりません。ある選択肢に応じて値を変数に設定したり、特定の条件に応じて何かを表示したりするとき、選択肢がたくさんあると、`if...else` ステートメントを書くのは面倒です。

`switch` ステートメントはそんなときの味方です。`switch` ステートメントは一つの式または値を受け取り、それに合致する値が見つかるまで選択肢を探します。そして合致した選択肢に対応するコードを実行します。まずは擬似コードを見て、雰囲気をつかみましょう。
```

switch ( 式 ) {
  case 選択肢1:
    このコードを実行する
    break;

  case 選択肢2:
    代わりにこのコードを実行する
    break;

  // 以下に選択肢を好きなだけ並べる

  default:
    既定でこのコードを実行する
}
```

上記のコードには...

1. `switch` キーワードに続き、一組の括弧があります。
2. 括弧の中には、式または値があります。
3. `case` キーワードに続き、選択肢となる式または値、それにコロン (`:`) が並んでいます。
4. もしその選択肢にマッチすれば、コードが実行されます。
5. `break` ステートメントとセミコロン (`;`) があります。もし前の選択肢にマッチして入ればブラウザーはコードの実行をここでやめ、switch ステートメントの後ろにあるコードに移動します。
6. `case` 節 (上記 3. から 5. ) は好きなだけ書くことができます。
7. 上記 3. から 5.の `case` 節と全く同じコードパターンで書かれている `default` キーワードがあります。違いは `default` の後ろに選択肢が書かれていないことです。また、後ろに続くコードがないので、ここには `break` ステートメントが必要ありません。もし、選択肢のどれにもマッチするものがない場合に既定のオプションとして実行されます。

**メモ:** 評価する式の値が不明な値にならないのであれば、`default` 節は書く必要はありません。しかし、式が不明な値となり、それに対処する必要があるのなら、`default` 節を書くことで対応が可能です。

### switch を使用する例

それでは実際の例を見てみましょう。先ほどの天気予報アプリを switch ステートメントを使用して書き直してみました。

```html
<label for="weather">今日の天気を選択してください: </label>
<select id="weather">
  <option value="">--選択してください--</option>
  <option value="sunny">晴れ</option>
  <option value="rainy">雨</option>
  <option value="snowing">雪</option>
  <option value="overcast">曇り</option>
</select>

<p></p>
```

```js
const select = document.querySelector("select");
const para = document.querySelector("p");

select.addEventListener("change", setWeather);

function setWeather() {
  const choice = select.value;

  switch (choice) {
    case "sunny":
      para.textContent =
        "今日はとてもいい天気です。短いパンツをはいて、砂浜や公園に出かけ、アイスクリームを食べましょう！";
      break;
    case "rainy":
      para.textContent =
        "雨が降っています。レインコートと傘を忘れないようにしましょう。";
      break;
    case "snowing":
      para.textContent =
        "雪が降ってとても寒いです！室内でホットチョコレートを飲むか、雪だるまを作るのがよいでしょう。";
      break;
    case "overcast":
      para.textContent =
        "雨は降っていませんが、空はとても暗くなっています。万が一に備えレインコートを持ちましょう。";
      break;
    default:
      para.textContent = "";
  }
}
```

**メモ:** このサンプルを GitHub で見ることができます。(実行可能なデモもあります。)

三項演算子
-----

例題に進む前に、ちょっとした構文をご紹介しましょう。三項演算子 (もしくは条件演算子) は条件式を判定し、その結果に応じて 2 つの値または式のうち、どちらか一方を返します。これはある状況においてはとても便利です。単純に `true`/`false` で判定可能な 2 つの選択肢のうちより片方を選ぶという場合には、`if...else` ブロックを書くよりも多くのコードを節約できます。この擬似コードは以下のようなものになります。
```

( 条件式 ) ? こちらのコードを実行する : 代わりにこちらのコードを実行する
```

それでは実際に例を見て見ましょう。

```js
let greeting = isBirthday
  ? "スミスさん、誕生日おめでとうございます！良い一日を。"
  : "スミスさんおはようございます。";
```

この例では `isBirthday` という変数があり、この変数が `true` の場合、お客に誕生日を祝福するメッセージを送ります。そうでなければ、通常の挨拶を送ります。

### 三項演算子を使用する例

三項演算子を変数の代入にのみ使用する必要はありません。関数や、複数行に渡るコードを実行する場合にも (それ以外にも好きなように) 使用できます。次の例は三項演算子を使用してサイトにテーマを適用しています。

```html
<label for="theme">テーマを選んでください: </label>
<select id="theme">
  <option value="white">白</option>
  <option value="black">黒</option>
</select>

<h1>私のウェブサイト</h1>
```

```js
const select = document.querySelector("select");
const html = document.querySelector("html");
document.body.style.padding = "10px";

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}

select.onchange = function () {
  select.value === "black"
    ? update("black", "white")
    : update("white", "black");
};
```

上記の例では、テーマ (黒または白) を選択することができる `<select>` 要素と、サイトのタイトルが書かれた単純な `<h1>` 要素があります。さらに `update()` という関数があり、その関数は引数 (入力値) として 2 つの色を取ります。この関数が呼ばれると、ウェブサイトの背景色は 1 つ目の引数に、文字の色は 2 つの目の引数に設定されます。

さらに、三項演算子を含む onchange イベントリスナーがあります。`select.value === 'black'` という条件式で始まっています。この式が `true` であるならば、`update()` 関数を引数に `'black'`、`'white'` を指定して実行します (つまり、背景色を黒、文字色を白に設定します)。この式が `false` であるならば、`update()` 関数を引数に `'white'`、`'black'` を指定して実行します (つまり、背景色を逆にします)。

**メモ:** この例は GitHub でも公開しています (または、動くデモもあります。)

アクティブ学習: 単純なカレンダー
-----------------

この例では、単純なカレンダーアプリケーションの作成を手伝ってもらいます。現在、以下の内容がコードに書かれています。

* ユーザーが月を選択できるように `<select>` 要素があります。
* `<select>` メニューの選択内容が変更された場合に、イベントを補足できるように `onchange` イベントハンドラーが設定されています。
* カレンダーを描画し、`<h1>` 要素に適切な月を設定する `createCalendar()` と呼ばれる関数があります。

あなたには、`onchange` ハンドラーの内部に条件式を書いてもらいます。`// 条件式をここに書く` というコメントのすぐ下に...

1. 選択されている月を取得します (これは `choice` 変数に格納されています。この値は `<select>` 要素で選択された後の値で、例えば 1 月なら、"1" といった値です。)
2. `days` という変数に、選択された月の日数を設定します。そのためには、1 年の各月の日数を調べる必要があるでしょう。うるう年はこの例題の目的から外れるため、無視してください。

ヒント:

* ほとんどの月は日数が同じなので、複数の月を OR 演算子を用いて一つの条件式にまとめるのが良いでしょう。
* どの月が最も多い日数なのか考えてください。そして、その日数をデフォルト値として使用しましょう。

もし間違ってしまっても、「リセット」ボタンを押すことでいつでも元に戻せます。詰まってしまったら、「答えを見る」ボタンで答えが見られます。
```

<h2>出力結果</h2>
<div class="output" style="height: 500px;overflow: auto;">
  <label for="month">月を選択してください: </label>
  <select id="month">
    <option value="1">1 月</option>
    <option value="2">2 月</option>
    <option value="3">3 月</option>
    <option value="4">4 月</option>
    <option value="5">5 月</option>
    <option value="6">6 月</option>
    <option value="7">7 月</option>
    <option value="8">8 月</option>
    <option value="9">9 月</option>
    <option value="10">10 月</option>
    <option value="11">11 月</option>
    <option value="12">12 月</option>
  </select>

  <h1></h1>

  <ul></ul>
</div>

<h2>コードエディタ</h2>
<p class="a11y-label">
  コードエディタから抜けるには Esc
  キーを押して下さい(タブキーではタブ文字を挿入します)。
</p>

<textarea id="code" class="playable-code" style="height: 400px;width: 95%">
const select = document.querySelector('select');
const list = document.querySelector('ul');
const h1 = document.querySelector('h1');

select.onchange = function() {
  const choice = select.value;

  // 条件式をここに書く

  createCalendar(days, choice + ' 月');
}

function createCalendar(days, choice) {
  list.innerHTML = '';
  h1.textContent = choice;
  for (let i = 1; i <= days; i++) {
    const listItem = document.createElement('li');
    listItem.textContent = i;
    list.appendChild(listItem);
  }
}

createCalendar(31,'1 月');
</textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="リセット" />
  <input id="solution" type="button" value="答えを見る" />
</div>
```

```
.output \* {
  box-sizing: border-box;
}

.output ul {
  padding-left: 0;
}

.output li {
  display: block;
  float: left;
  width: 25%;
  border: 2px solid white;
  padding: 5px;
  height: 40px;
  background-color: #4a2db6;
  color: white;
}

html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "答えを見る";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "答えを見る") {
    textarea.value = solutionEntry;
    solution.value = "答えを隠す";
  } else {
    textarea.value = userEntry;
    solution.value = "答えを見る";
  }
  updateCode();
});

const jsSolution =
  "const select = document.querySelector('select');\nconst list = document.querySelector('ul');\nlet h1 = document.querySelector('h1');\n\nselect.onchange = function() {\n let choice = select.value;\n let days = 31;\n if(choice === '2') {\n days = 28;\n } else if(choice === '4' || choice === '6' || choice === '9'|| choice === '11') {\n days = 30;\n }\n\n createCalendar(days, choice + ' 月');\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = '';\n h1.textContent = choice;\n for(let i = 1; i <= days; i++) {\n let listItem = document.createElement('li');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,'1 月');";
let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// タブキーでテキストエリアから抜けてしまうのを防ぎ、
// 代わりにカーソル位置にタブ文字を挿入する

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  const caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );
  textarea.value = front + text + back;
  caretPos = caretPos + text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// ユーザーがテキストエリアのコードを書き換える度に userCode を毎回更新する

textarea.onkeyup = function () {
  // ユーザーのコードが表示されているときのみ状態を保存し、
  // 答えのコードでユーザーコードが上書きされないようにする
  if (solution.value === "答えを見る") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

アクティブ学習: もっとたくさんの色から選ぶ！
-----------------------

この例では、先ほどの三項演算子の例を switch ステートメントに変換し、単純なウェブサイトに、より多くの選択肢を与えます。`<select>` 要素を見てください。今回は先ほどの 2 つではなく、5 つの選択肢があります。`// ここに SWITCH ステートメントを書く` というコメントの真下に switch ステートメントを追加してください。

* `choice` 変数を判定する式として使用します。
* 各ケース (case) で、`choice` 変数は選択可能な値 ('white'、'black'、'purple'、'yellow'、'psychedelic') のうちのどれかです。
* 各ケース (case) で、`update()` 関数が実行されるようにしてください。関数には 2 つの引数を指定します。1 つ目の引数は背景色、2 つ目の色は前景色です。色は文字列なので、忘れずに引用符で囲みましょう。

もし間違ってしまっても、「リセット」ボタンを押すことでいつでも元に戻せます。詰まってしまったら、「答えを見る」ボタンで答えが見られます。
```

<h2>出力結果</h2>
<div class="output" style="height: 300px;">
  <label for="theme">テーマを選んでください: </label>
  <select id="theme">
    <option value="white">白</option>
    <option value="black">黒</option>
    <option value="purple">紫</option>
    <option value="yellow">黄</option>
    <option value="psychedelic">サイケ</option>
  </select>

  <h1>私のウェブサイト</h1>
</div>

<h2>コードエディタ</h2>
<p class="a11y-label">
  コードエディタから抜けるには Esc
  キーを押して下さい(タブキーではタブ文字を挿入します)。
</p>

<textarea id="code" class="playable-code" style="height: 450px;width: 95%">
const select = document.querySelector('select');
const html = document.querySelector('.output');

select.onchange = function() {
  const choice = select.value;

  // ここに SWITCH ステートメントを書く
}

function update(bgColor, textColor) {
  html.style.backgroundColor = bgColor;
  html.style.color = textColor;
}</textarea
>

<div class="playable-buttons">
  <input id="reset" type="button" value="リセット" />
  <input id="solution" type="button" value="答えを見る" />
</div>
```

```
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  eval(textarea.value);
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = jsSolution;
  solution.value = "答えを見る";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "答えを見る") {
    textarea.value = solutionEntry;
    solution.value = "答えを隠す";
  } else {
    textarea.value = userEntry;
    solution.value = "答えを見る";
  }
  updateCode();
});

const jsSolution =
  "const select = document.querySelector('select');\nconst html = document.querySelector('.output');\n\nselect.onchange = function() {\n const choice = select.value;\n\n switch(choice) {\n case 'black':\n update('black','white');\n break;\n case 'white':\n update('white','black');\n break;\n case 'purple':\n update('purple','white');\n break;\n case 'yellow':\n update('yellow','darkgray');\n break;\n case 'psychedelic':\n update('lime','purple');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}";
let solutionEntry = jsSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// タブキーでテキストエリアから抜けてしまうのを防ぎ、
// 代わりにカーソル位置にタブ文字を挿入する

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  const caretPos = textarea.selectionStart;
  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );
  textarea.value = front + text + back;
  caretPos = caretPos + text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// ユーザーがテキストエリアのコードを書き換える度に userCode を毎回更新する

textarea.onkeyup = function () {
  // ユーザーのコードが表示されているときのみ状態を保存し、
  // 答えのコードでユーザーコードが上書きされないようにする
  if (solution.value === "答えを見る") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

スキルテスト
------

この記事の最後まで来ましたが、最も大事な情報を覚えていますか？先に進む前に、この情報を保持しているか検証するテストがあります — Test your skills: Conditionals を見てください。

まとめ
---

これで JavaScript での条件構造について今知っておくべきことはすべてです！簡単な例を通してそのコンセプトが理解できたと思います。もし理解できないことがあれば、何度も記事を読み返しましょう。私たちに連絡をしても構いません。

関連情報
----

* 比較演算子
* 条件式についての詳細
* if...else リファレンス
* 条件 (三項) 演算子リファレンス
* Overview: Building blocks
* 次のページ


イメージギャラリー - ウェブ開発を学ぶ

イメージギャラリー
=========

* 前のページ
* Overview: Building blocks

JavaScript の基本的な構成要素を見てきたところで、これからたくさんのウェブサイトで見かける項目、JavaScript で動作するイメージギャラリーをつくってみることで、あなたが得た繰り返し、関数、条件とイベントの知識を試してみましょう。

| 前提条件: | この評価を行う前に、このモジュールにある記事すべてを実施していること。 |
| --- | --- |
| 目標: | JavaScript の繰り返し、関数、条件とイベントが理解できていることを確認する。 |

出発点
---

この評価を始めるために、サンプルが入っているサイトから ZIP ファイル を取得して、コンピュータのどこかに展開しておきます。

**メモ:** 別の方法として, この評価を行うために JSBin や Thimble のようなサイトを使うことができます。これらのオンラインエディターに HTML、CSS、JavaScript を貼り付けることができます。利用するオンラインエディターが JavaScript/CSS パネルに分かれていなければ、 HTML ページの中の `<script>`/`<style>` 要素にそれらを貼り付けてください 。

プロジェクト概要
--------

HTML、CSS と画像および数行の JavaScript のコードが提供されています。必要な JavaScript を書いて、これを動くプログラムにする必要があります。HTML のボディは次のようになっています:

```html
<h1>Image gallery example</h1>

<div class="full-img">
  <img class="displayed-img" src="images/pic1.jpg" />
  <div class="overlay"></div>
  <button class="dark">Darken</button>
</div>

<div class="thumb-bar"></div>
```

例ではこのように見えます:

![](/ja/docs/Learn/JavaScript/Building_blocks/Image_gallery/gallery.png)

例にある CSS ファイルで最も興味深い部分:

* `full-img <div>` の内側に 3 つの要素が絶対位置指定されています ー `<img>` にはフルサイズの画像が表示されています。その上に `<img>` と同じサイズになるようにサイズ調整された空の`<div>` が置かれています (これは半透明の背景色で画像を暗くする効果に使われます)。そして `<button>` は暗くする効果をコントロールするために使われます。
* `thumb-bar <div>` (いわゆるサムネイル画像) 内の画像は幅を 20% に設定し、左側に浮かせて一行に並べています。

JavaScript に必要なもの:

* すべての画像をループさせる際、`thumb-bar <div>` の中にその画像を埋め込む `<img>` 要素を挿入します。
* `onclick` ハンドラーを `thumb-bar <div>` の中の `<img>` それぞれにつけます。それをクリックしたときにその画像が `displayed-img <img>` 要素に表示されるようにします。
* `onclick` ハンドラーを `<button>` につけて、クリックされたらフルサイズ画像を暗くするようにします。再度クリックすると暗くする効果を外します。

もっとアイデアを加えると、最終的な例 のようになります (ソースコードをのぞかないように！)

完成へのステップ
--------

次のセクションですべきことを説明します。

### 画像をループさせる

すでに `thumbBar` という変数に `thumb-bar <div>` の参照を格納するようにしています。新しい `<img>` 要素を作って、その `src` 属性にプレースホルダーとして値 `xxx` をセットしてください。そして、新しい `<img>` 要素を `thumbBar` に追加してください。

必要なこと:

1. "Looping through images" コメントの下のセクションのコードを全 5 画像をループする繰り返し処理のなかに置いて下さい — 各画像を表現する 5 つの数についてループするだけです。
2. 各ループの反復で、プレースホルダー `xxx` の値を画像のパスに等しい文字列で置き換えてください。それぞれの場合で `src` 属性の値をこの値に設定します。いずれの場合も画像は画像ディレクトリーにあり、`pic1.jpg`、`pic2.jpg` というようなファイル名になっています。
### onclick ハンドラーをそれぞれのサムネール画像に追加する

各ループの反復で、現在の `newImage` に `onclick` ハンドラーを追加する必要があります — このハンドラは現在の画像の `src` 属性の値を見つけます。`displayed-img <img>` の `src` 属性の値をパラメータとして渡されたものの `src` 値へ設定します。

替わりに、サムネイルバーへ一つのイベントリスナーを追加することも出来ます。

### 暗くする/明るくするボタンを処理するハンドラーを書く

暗くする/明るくする `<button>` が残っています。`btn` という変数に `<button>` への参照を格納するコードはすでにご紹介しています。それらに `onclick` ハンドラーに追加する必要があります:

1. `<button>` にセットされている現在のクラス名をチェックしますーこれもまた、`getAttribute()` を使えば取得できます。
2. クラス名が `"dark"` なら、`<button>` のクラスを (`setAttribute()` を使って) `"light"` に変更します。テキストも "Lighten" にします。そして、オーバーレイ `<div>` の `background-color` を `"rgba(0,0,0,0.5)"` にします。
3. クラス名が `"dark"` でなければ、`<button>` のクラスを `"dark"` に変更します。テキストを "Darken" に戻します。そしてオーバーレイ `<div>` の `background-color` を `"rgba(0,0,0,0)"` にします。

次のコードは上記の 2 と 3 で示された変更を行う基本的なものです。

```js
btn.setAttribute("class", xxx);
btn.textContent = xxx;
overlay.style.backgroundColor = xxx;
```

ヒントとコツ
------

* HTML と CSS は全く編集する必要はありません。
課題
--

組織されたコースの一部としてこの評価を行う場合、採点のため先生/メンターにあなたの成果を提出してください。もし、自習なら、このエクササイズに関するディスカッションのスレッド や Mozilla IRC の #mdn IRC チャネルで尋ねれば、採点ガイドが簡単に得られるでしょう。まずエクササイズに挑戦してください。ーごまかしても何も得られません！

* 前のページ
* Overview: Building blocks


独自の関数を作る - ウェブ開発を学ぶ

独自の関数を作る
========

* 前のページ
* Overview: Building blocks
* 次のページ

前の記事で扱った重要な理屈をたくさん使って、この記事では実践的な練習を行ないます。ここではあなたが自力で独自関数を作成するための練習を行なっていきます。同時に、関数を扱う上で役に立つ細々の説明もしていきます。

| 前提知識: | 基本的なコンピューターの知識、HTML と CSS への理解、JavaScript の第一歩、関数 — 再利用可能なコードブロック。 |
| --- | --- |
| 目的: | 独自の関数を作成する練習、役に立つ関連事項についてつっこんだ説明。 |

Active learning: 関数を作ってみよう
--------------------------

これから作ってみる独自の関数を `displayMessage()`。これは独自のメッセージボックスをウェブページ上に表示し、ブラウザー組込みの alert() 関数の特製の代替品として動作します。既に見たものですが、忘れた事にしましょう。以下をブラウザーの JavaScript コンソールから打ち込みます、どのページでも構いません:

```js
alert("This is a message");
```

`alert` 関数は引数を一つ取ります — アラートボックスに表示される文字列です。文字列を色々変えてメッセージを変化させてみて下さい。

`alert` 関数には制限があります: メッセージを変更することはできますが、色やアイコンなど、それ以外の部分を簡単には変えられません。もっと楽しくできるやつを作りましょう。

**メモ:** この例題は全てのモダンブラウザー上で問題なく動くはずですが、古いブラウザーではちょっとおかしな見た目になるかもしれません。この課題は Firefox、Opera、Chrome のようなモダンなブラウザー上で行なうのが推奨です。

基本的な関数
------

最初に、基本的な関数を組み立てていきましょう。

**メモ:** 関数に名前を付ける方針としては、変数名に名前をつける方針と同じルールに従うべきです。問題はありません、すぐに見分けがつくからです — 関数ならすぐ後に括弧が付きますが、変数には付きません。

1. function-start.html ファイルにアクセスして、ローカルコピーを作成するところから初めます。HTML は単純です — body にはボタン一つしかありません。特製メッセージボックス用の基本的な CSS スタイルと、JavaScript を追加していく用の空の `<script>` 要素が含まれています。
2. 次に、`<script>` 要素の中に以下を追加して下さい:

```js
function displayMessage() {}
```

キーワード `function` から始めますが、これは関数を定義するという意味です。この後には、関数につけたい名前、カッ括弧の組、中括弧の組と続きます。関数に渡したい引数は括弧の中に、関数を呼び出したときに走らせたいコードは中括弧の中に書きます。
3. 最後に、以下のコードを中括弧の中に追加します:

```js
const html = document.querySelector("html");

const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
html.appendChild(panel);

const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);

const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);

closeBtn.onclick = function () {
  panel.parentNode.removeChild(panel);
};
```

これは見ていくにはそこそこの量のコードですから、一つ一ついっしょに進んでいく事にしましょう。

最初の行では `document.querySelector()` と呼ばれる DOM API 関数を使って `<html>` 要素を選択し、`html` という名前の定数に要素への参照を保存したので、これを使っていろいろやっていきます:

```js
const html = document.querySelector("html");
```

次の部分では別の DOM API 関数 `document.createElement()` を使い、`<div>` 要素を作成、これへの参照を `panel` という定数に保存しています。この要素は我々のメッセージボックスの外枠となっていきます。

次にまた別の DOM API 関数 `Element.setAttribute()` を使って、我々のパネルの `class` 属性とその値 `msgBox` を設定します。これは要素のスタイルを指定しやすくするためです — ページの CSS を見ると、メッセージボックスとその中身に適用するスタイルとして `.msgBox` クラスセレクターがあるのがわかるでしょう。

最後に、前に保存した html 変数の DOM 関数 `Node.appendChild()` を呼んでいますが、この関数は一つの要素を別の要素の子として組み入れる働きをします。panel という`<div>` 要素を子として、`<html>` 要素の中に追加したいのです。作成した要素は作成したページにぽんと現われたりはしません — どこに置くのかも指定しなければなりません。なのでこのようにする必要があります。

```js
const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
html.appendChild(panel);
```

次の 2 つのセクションでは既に見た同じ `createElement()` と `appendChild()` 関数を使用して、2 つの新しい要素、つまり `<p>` と `<button>` を作成し、`<div>` パネルの子要素としてページに挿入します。段落の中にメッセージを挿入する `Node.textContent` プロパティ (要素のテキスト内容を表す) とボタンの中に 'x' を使います。このボタンは、ユーザーがメッセージボックスを閉じるときにクリック/アクティブ化する必要があります。

```js
const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);

const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);
```

最後に、`GlobalEventHandlers.onclick` イベントハンドラーを使用して、ボタンをクリックするとパネル全体をパネルから削除してメッセージボックスを閉じるようにします。

簡単に説明すると、`onclick` ハンドラーはボタン (または実際にはページ上の任意の要素) で使用できるプロパティで、ボタンをクリックしたときに実行するコードを指定する関数に設定できます。後のイベントの記事で、これらについてさらに詳しく学びます。`onclick` ハンドラーは、ボタンがクリックされたときに実行されるコードを含む無名関数と等しくなります。関数内の行は `Node.removeChild()` DOM API 関数を使用して、HTML 要素の特定の子要素 (この場合は `<div>` パネル) を削除することを指定します。

```js
closeBtn.onclick = function () {
  panel.parentNode.removeChild(panel);
};
```

基本的には、このコードブロック全体が HTML のブロックを生成してページに挿入しています。

```html
<div class="msgBox">
  <p>This is a message box</p>
  <button>x</button>
</div>
```

作業するコードがたくさんありました。今のところどのように動作しているか正確に覚えていないことをあまり心配しないでください！ ここでは、関数の構造と使用法を中心に説明しますが、この例では何か面白いことを示したかったのです。

関数の呼び出し
-------

これで、`<script>` 要素に書かれた関数定義がうまくいきましたが、それは何もしません。

1. 関数の下に次の行を含めて呼び出してみてください:

```js
displayMessage();
```

この行は関数を呼び出し、すぐに実行させます。コードを保存してブラウザーを再読み込みすると、小さなメッセージボックスがすぐに 1 回だけ表示されます。それを一度呼ぶだけです。
2. サンプルページでブラウザーの開発者ツールを開き、JavaScript コンソールに移動してもう一度その行を入力すると、もう一度表示されます。これは楽しいことです - 私たちは今好きな時に呼び出すことができる再利用可能な関数を持っています。
 しかし、ユーザーとシステムのアクションに応じて表示されるようにすることをお勧めします。実際のアプリケーションでは、このようなメッセージボックスは、新しいデータが利用可能であること、エラーが発生したこと、ユーザーがプロファイルを削除しようとしている (「これは本当ですか？」)、またはユーザーが 新しい連絡先や操作が正常に終了しました...などが起こったときに呼び出されるでしょう。
 このデモでは、ユーザーがボタンをクリックするとメッセージボックスが表示されます。
3. 追加した前の行を削除します。
4. 次に、ボタンを選択し、そのボタンへの参照を定数に格納します。関数定義の上のコードに次の行を追加します:

```js
const btn = document.querySelector("button");
```

5. 最後に、前の行の下に次の行を追加します:

```js
btn.onclick = displayMessage;
```

関数内の `closeBtn.onclick...` 行と同様に、ここではボタンがクリックされたことに応答してコードを呼び出します。しかしこの場合、コードを含む無名関数を呼び出す代わりに、関数名を直接呼び出しています。
6. ページを保存して再表示してみてください。ボタンをクリックするとメッセージボックスが表示されるはずです。

関数名の後ろに括弧が含まれていないのはなぜでしょうか。これは、ボタンがクリックされた後にのみ、関数をすぐに呼びたくないからです。行を次の行に変更しようとすると

```js
btn.onclick = displayMessage();
```

保存して再読み込みすると、ボタンをクリックせずにメッセージボックスが表示されます。このコンテキストの括弧は「関数呼び出し演算子」と呼ばれることがあります。現在のスコープですぐに関数を実行する場合にのみ使用します。同様の点で、匿名関数内のコードは関数スコープ内にあるため、すぐには実行されません。

最後の実験を試した場合は、最後の変更を取り消してから実行してください。

パラメーターを使用して関数を改善する
------------------

その機能はそれほど便利ではありません — 毎回同じ既定のメッセージを表示したくはないのです。いくつかのパラメーターを追加して機能を改善し、いくつかの異なるオプションで呼び出すことができるようにしましょう。

1. まず、関数の最初の行を更新します。

```js
function displayMessage() {
```

このようになります:

```js
function displayMessage(msgText, msgType) {
```

関数を呼び出すと、括弧内に 2 つの変数値を指定して、メッセージボックスに表示するメッセージとそのメッセージのタイプを指定できます。
2. 最初のパラメーターを使用するには、関数内の次の行を更新します:

```js
msg.textContent = "This is a message box";
```

このようになります

```js
msg.textContent = msgText;
```

3. 最後に関数呼び出しを更新して、更新されたメッセージテキストを追加する必要があります。次の行を変更します。

```js
btn.onclick = displayMessage;
```

このブロックのようになります:

```js
btn.onclick = function () {
  displayMessage("Woo, this is a different message!");
};
```

私たちが呼び出している関数の括弧内にパラメーターを指定したい場合、直接呼び出すことはできません - 直接のスコープにないため、すぐに呼び出されないように無名関数の中に入れる必要があります。ボタンがクリックされるまで呼び出されません。
4. 再読み込みしてコードをもう一度試してみてください。それでもパラメーター内のメッセージを変えてボックスに表示されるメッセージを変えることができます。
### より複雑なパラメーター

次のパラメーターに移りましょう。これにはもう少し作業が必要です。`msgType` パラメーターの設定によって、別のアイコンと異なる背景色が表示されるように設定していきます。

1. まず始めに、この演習に必要なアイコン (warning と chat) を GitHub からダウンロードしてください。HTML ファイルと同じ場所にある `icons` という新しいフォルダーに保存します

**メモ:** iconfinder.com にある warning と chat のアイコンは Nazarrudin Ansyari によってデザインされたものです。ありがとう！ (実際のアイコンのページは移動か削除されています。)
2. 次に、HTML ファイル内の CSS を探します。私たちは、アイコンの道を作るためにいくつかの変更を行います。まず `.msgBox` の幅を次のように更新します

```css
width: 200px;
```

このようにします

```css
width: 242px;
```

3. 次に、`.msgBox p { ... }` ルール内に次の行を追加します

```css
padding-left: 82px;
background-position: 25px center;
background-repeat: no-repeat;
```

4. これでアイコンの表示を処理するために、`displayMessage()` 関数にコードを追加する必要があります。関数の終了中括弧 (`}`) のすぐ上に次のブロックを追加します。

```js
if (msgType === "warning") {
  msg.style.backgroundImage = "url(icons/warning.png)";
  panel.style.backgroundColor = "red";
} else if (msgType === "chat") {
  msg.style.backgroundImage = "url(icons/chat.png)";
  panel.style.backgroundColor = "aqua";
} else {
  msg.style.paddingLeft = "20px";
}
```

ここで、`msgType` パラメーターが `'warning'` に設定されている場合、警告アイコンが表示され、パネルの背景色は赤に設定されます。`'chat'`に設定されている場合、チャットアイコンが表示され、パネルの背景色が青色に設定されます。`msgType` パラメーターがまったく設定されていない (または別のものに変更されている) 場合、コードの `else { ... }` 部分が有効になり、段落には単にデフォルトのパディングが与えられ、背景パネルの色もしくはアイコンのどちらかが未設定の状態となります。これは `msgType` パラメーターが指定されていない場合、省略可能なパラメーターであることを意味するデフォルトの状態を提供します。
5. 更新された関数をテストしましょう。この `displayMessage()` 呼び出しを更新して：

```js
displayMessage("Woo, this is a different message!");
```

これらのうちの 1 つにしましょう。

```js
displayMessage("Your inbox is almost full — delete some mails", "warning");
displayMessage("Brian: Hi there, how are you today?", "chat");
```

私たちの (今はそうではない) 小さな機能がどのように役立つかがわかります。

**メモ:** サンプルをうまく動作させることができない場合は、コードを GitHub の完成バージョンと比較して (see it running live もみて) チェックしてください。もしくは私たちにヘルプを依頼してください。

スキルをテストしよう!
-----------

この記事の最後まで到達しましたが、最も大事な情報を覚えていますか？移動する前に、この情報を維持しているか検証するテストを見ることができます— Test your skills: Functions (en-US). を見てください。このテストは次の記事でカバーするスキルが必要ですので、試す前にこれを読んでおくとよいでしょう。

まとめ
---

最後までたどり着きました。おめでとうございます！この記事では、実用的なカスタム関数を構築するプロセス全体を紹介しました。もう少し動けば、実際のプロジェクトに移植することができます。次の記事では、別の重要な関連概念である戻り値を説明して関数をまとめます。

* 前のページ
* Overview: Building blocks
* 次のページ


イベント入門 - ウェブ開発を学ぶ

イベント入門
======

* 前のページ
* Overview: Building blocks
* 次のページ

イベントは、あなたがプログラミングしているシステムで起こることで、あなたのコードがそれらに反応できるようにシステムがあなたに伝えるものです。

例えば、ユーザーがウェブページ上でボタンを押したとき、ある情報を表示するように反応させたいと思うかもしれません。この記事では、イベントに関する重要な概念を取り上げ、ブラウザーの中でのイベントの振る舞いを見ていきます。ここでは、全てを説明するのではなく、この段階で知っておくべき内容を取り上げます。

|  |  |
| --- | --- |
| 前提条件: |
 基本的なコンピューターリテラシー、基本的な HTML および CSS、
 JavaScript の第一歩について理解していること。
  |
| 目的: | イベントの基本的な理論を理解すること。ブラウザーでの振る舞いを理解し、プログラミング環境が変わると、イベントの振る舞いが変わることを理解すること。 |

イベントとは何か
--------

 イベントは、あなたがプログラミングしているシステムで発生するものです。イベントが発生すると、システムは何らかのシグナルを発生（または「発火」）させ、イベントが発生したときに自動的にアクションが実行される（つまり、何らかのコードが実行される）メカニズムを提供します。
 イベントはブラウザーウィンドウの内部で発生し、そこに存在する特定のアイテムに結び付けられる傾向があります。これは単一の要素であったり、要素の集合であったり、現在のタブ内に読み込まれた HTML 文書であったり、ブラウザーウィンドウ全体であったりします。
 発生するイベントにはさまざまな種類があります。

例えば、次のような者があります。

* ユーザーが特定の要素を選択したり、クリックしたり、カーソルを当てたりする
* ユーザーがキーボードのキーを押す
* ユーザーがブラウザーウィンドウをリサイズしたり閉じたりする
* ウェブページの読み込みが完了する
* フォームが送信される
* 動画が再生される、停止される、再生が終わる
* エラーが発生する

ここから（そして MDN のイベントリファレンスから）、発生するイベントが**たくさん**あることがわかります。

 イベントに反応するには、イベントに**イベントハンドラー**を取り付けます。これは、イベントが発行されたときに実行するコードのブロック（通常はプログラマーであるあなたが作成する JavaScript 関数）です。
 このようなコードのブロックが、イベントに応答して実行するように定義されている場合、**イベントハンドラーを登録**していると言います。
 なお、イベントハンドラーは時に **イベントリスナー** と呼ばれることがあります。目的からすれば言い換えてもほとんど問題ないのですが、厳密に言えば一緒に動作する別のものです。イベントリスナーはイベントの発生を待ち受けし、イベントハンドラーは発生したイベントに応答して動作するコードです。

**メモ:** ウェブのイベントは JavaScript のコア言語の一部ではありません。それらはブラウザーに組み込まれた API の一部として定義されています。

### 例: クリックイベントの扱い

次の例では、ページ内に単一の `<button>` があります。

```html
<button>色を変更</button>
```

```
button {
  margin: 10px;
}
```

次に JavaScript が少しあります。この詳細は次の章で見ていきますが、これで言えることは、ボタンの `"click"` イベントにイベントハンドラーを追加し、そのハンドラーがページの背景をランダムな色に設定することでイベントに反応しているということです。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

btn.addEventListener("click", () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});
```

出力例は以下です。ボタンをクリックしてみてください。

addEventListener() の使用
----------------------

最後の例で見たように、イベントを発行することができるオブジェクトは `addEventListener()` メソッドを持っており、これはイベントハンドラーを追加するための推奨メカニズムです。

前回の例のコードを詳しく見ていきましょう。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

btn.addEventListener("click", () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});
```

HTML の `<button>` 要素は、ユーザーがボタンをクリックするとイベントを発生します。そのため、 `addEventListener()` 関数を定義し、ここで呼び出しています。引数を 2 つ渡しています。

* 文字列 `"click"` で、クリックイベントを待ち受けしたいことを示します。ボタンは他にもたくさんのイベントを発行することができます。例えば、ユーザーがマウスをボタンの上に移動させたときに `"mouseover"` を発行したり、ユーザーがキーを押してボタンにフォーカスが当たったときに `"keydown"` を発行したりすることができます。
* イベント発生時に呼び出す関数です。この場合、この関数はランダムな RGB の色を生成し、ページの `<body>`(/ja/docs/Web/HTML/Element/body) の `background-color` をその色に設定します。

ハンドラー関数を別の名前付き関数にするのは問題ありません。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

function changeBackground() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

btn.addEventListener("click", changeBackground);
```

### 他のイベントの待ち受け

利用できるイベントハンドラープロパティにはとてもたくさんの種類があります。実験してみましょう。

まずは、 random-color-addeventlistener.html のローカルコピーを作成し、ブラウザーで開いてみてください。これはこの記事ですでに遊んだ、簡単なランダムカラーのサンプルです。さて、 `click` のところを以下の異なる値に変えてみて、結果を順に見てみてください。

* `focus` と `blur` —タブを押すとボタンがフォーカスされ、もう一度タブを押すとボタンからフォーカスが外れます。
 これらは、フォームフィールドがフォーカスされたときに、フォームフィールドへの入力に関する情報を表示したり、フォームフィールドに誤った値が入力された場合にエラーメッセージを表示したりするために多く使用されます。
* `dblclick` — ダブルクリックされた場合だけ色が変わります。
* `mouseover` と `mouseout` — それぞれ、マウスポインターがボタンの上に来たときとボタンの上から外れた時に色が変わります。

一部のイベント、たとえば `click` などは、ほぼすべての要素で利用できます。他のイベントはより具体的で、特定の状況でのみ使用することができます。例えば、`play` イベントは `<video>` のようないくつかの要素でのみ利用することができます。

### リスナーの除去

`addEventListener()` を用いてイベントハンドラーを追加した場合、`removeEventListener()` メソッドを用いて再び除去することができます。例えば、この例では `changeBackground()` イベントハンドラーが除去されます。

```js
btn.removeEventListener("click", changeBackground);
```

 イベントハンドラーは `AbortSignal` を `addEventListener()` に渡して、後で `abort()` を呼び出すことでも除去できます。
 例えば、 `AbortSignal` で除去されるイベントハンドラーを追加するには、次のようにします。

```js
const controller = new AbortController();

btn.addEventListener("click",
  () => {
    const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
    document.body.style.backgroundColor = rndCol;
  },
  { signal: controller.signal } // このハンドラーに AbortSignal を渡す
);
```

すると、上のコードで作成したイベントハンドラーは、次のように除去されます。

```js
controller.abort(); // このコントローラーに関連付けられたすべてのイベントを除去
```

 単純で小さなプログラムでは、古くて使われていないイベントハンドラーをクリーンアップする必要はありませんが、大規模で複雑なプログラムでは、効率を向上させることができます。
 また、イベントハンドラーを除去する機能により、同じボタンが異なる状況で異なるアクションをするようなことも可能です。ハンドラーを追加したり除去されたりするだけです。

### 単一のイベントに複数の待ち受けを追加

`addEventListener()` に複数の呼び出しを行うことで、異なるハンドラーを提供し、単一のイベントに複数のハンドラーを持たせることができます。

```js
myElement.addEventListener("click", functionA);
myElement.addEventListener("click", functionB);
```

これで要素がクリックされると両方の関数が実行されるようになりました。

### さらに学ぶ

他にも `addEventListener()` で利用できる強力な機能やオプションがあります。

これらはこの記事の範囲からは少し外れますが、もし読みたければ、 `addEventListener()` と `removeEventListener()` のリファレンスページを参照してください。

イベントリスナーの他の機構
-------------

イベントハンドラーの登録には `addEventListener()` を使用することを推奨します。これは最も強力なメソッドで、より複雑なプログラムで最も有効に機能します。しかし、イベントハンドラーを登録する方法として、他にも 2 種類あります。イベントハンドラープロパティとインラインイベントハンドラーです。

### イベントハンドラープロパティ

 イベントを発行することができるオブジェクト（ボタンなど）は通常、 `on` にイベント名が続くプロパティを持っています。例えば、要素には `onclick` というプロパティがあります。
 これは、イベントハンドラープロパティと呼ばれます。イベントを待ち受けるには、ハンドラー関数をプロパティに割り当てることで実現できます。

例えば、ランダムカラーの例を次のように書き換えることができます。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

btn.onclick = () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
};
```

ハンドラープロパティには名前付き関数を設定することもできます。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

btn.onclick = bgChange;
```

イベントハンドラープロパティでは、単一のイベントに複数のハンドラーを追加することはできません。例えば、 `addEventListener('click', handler)` は 1 つの要素に対して複数回、第 2 引数に異なる関数を指定して呼び出すことができます。

```js
element.addEventListener("click", function1);
element.addEventListener("click", function2);
```

イベントハンドラープロパティでは、後からプロパティを設定しようとすると、それ以前のものが上書きされてしまうため、これは不可能です。

```js
element.onclick = function1;
element.onclick = function2;
```

### インラインイベントハンドラー — 使用しないでください

あなたのコードにもこのようなパターンがあるかもしれません。

```html
<button onclick="bgChange()">Press me</button>
```

```js
function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}
```

 イベントハンドラーを登録するための最も初期の方法は、 HTML のイベントハンドラー属性（またはインラインイベントハンドラー）を使うものでした。属性の値は、文字通り、イベントが発生したときに実行したい JavaScript コードです。
 上記の例では、同じページの `<script>` 要素の中で定義した関数を呼び出していますが、例えば次のように、属性の中に直接 JavaScript を挿入することもできます。

```html
<button onclick="alert('Hello, this is my old-fashioned event handler!');">
  Press me
</button>
```

 イベント ハンドラー プロパティの多くに対応する HTML 属性が見つかりますが、これらを使用すべきではありません。これらは悪い習慣と見なされています。
 イベントハンドラー属性を使用することは、実に素早く何かを行う場合には簡単に思えるかもしれませんが、すぐに手に負えなくなり、非効率的になります。

まず、 HTML と JavaScript を混在させるのは良い考えとは言えません。 JavaScript を分けておくことは良い習慣です。 JavaScript を別のファイルにすれば、複数の HTML 文書に適用することができます。

 単一のファイルであっても、インラインイベントハンドラーはよい考えではありません。
 ボタンが 1 つなら問題ありませんが、 100 個のボタンがあったとしたらどうでしょう？ファイルに 100 個の属性を追加しなければならず、すぐにメンテナンスの悪夢に変わるでしょう。
 JavaScript では、次のようなものを使用して、ページ上のすべてのボタンにイベントハンドラー関数を追加することができます。

```js
const buttons = document.querySelectorAll("button");

for (const button of buttons) {
  button.addEventListener("click", bgChange);
}
```

最後に、多くの一般的なサーバー設定は、セキュリティ対策としてインラインJavaScriptを許可しません。

**HTMLのイベントハンドラー属性を使用しないようにしましょう**。これらは時代遅れで、使用するのは悪い習慣です。

イベントオブジェクト
----------

 ときどきイベントハンドラー関数内で `event`、`evt`、`e` などと名付けられた引数を見かけるでしょう。
 これらは**イベントオブジェクト**と呼ばれ、イベントの追加機能や情報を提供する目的でイベントハンドラーに自動的に渡されます。
 例えば、またランダムカラーの例をちょっと書き換えてみましょう。

```js
const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() \* (number + 1));
}

function bgChange(e) {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}

btn.addEventListener("click", bgChange);
```

**メモ:** この例の完全なソースコードが GitHub 上にあります（また、ライブ実行を見ることができます）。

 イベントオブジェクト **e** が関数に含まれていて、関数内で `e.target` — これはボタン自身 — の背景色スタイルを設定しているのがわかるでしょう。
 イベントオブジェクトの `target` プロパティは、常にイベントが生じた要素への参照となっています。
 ですから、この例ではページではなく、ボタンの背景色がランダムに変わります。

**メモ:** 下記のイベントの移譲の節で、 `event.target` を使用している例があります。

**メモ:** イベントオブジェクトには好きな名前が使えます。イベントハンドラー関数のカッコの中に使いたい名前を書くだけです。
 `e`/`evt`/`event` が開発者の間でとても良く使われていますが、これらが短くて覚えやすいからです。
 常に一貫性を保つことは良いことです。自分自身に対しても、可能であれば他の人に対しても。

### イベントオブジェクトの追加プロパティ

ほとんどのイベントオブジェクトは、イベントオブジェクトで利用できるプロパティとメソッドの標準設定を持っています。完全なリストは `Event` オブジェクトリファレンスを参照してください。

イベントオブジェクトの中には、そのイベントの特定の種類に関連するプロパティを追加するものがあります。例えば、 `keydown` イベントは、ユーザーがキーを押した時に発行されます。そのイベントオブジェクトは `KeyboardEvent` で、どのキーが押されたかを指示する `key` プロパティを持った `Event` オブジェクトです。

```html
<input id="textBox" type="text" />
<div id="output"></div>
```

```js
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
  output.textContent = `"${event.key}" が押されました。`;
});
```

```
div {
  margin: 0.5rem 0;
}
```

テキストボックスに入力して出力を見てください。

既定の動作の抑制
--------

 時々、あるイベントで既定で行われることを抑止したくなるような場合があります。
 最も一般的な例は、例えばカスタム登録フォームのようなウェブフォームです。
 詳細を入力して送信ボタンをクリックすると、データは処理のためにサーバー上の指定したページに送信され、ブラウザーは何らかの「成功メッセージ」ページ（または別のページが指定されていない場合は同じページ）にリダイレクトされるのが自然な動作です。

ユーザーが適切なデータを送信しなかった場合に問題が発生します。開発者として、サーバーへのデータ送信を抑止し、どこに問題があってデータを適切なものにするにはどうすればいいのか示す、ユーザーへのエラーメッセージを表示したいことでしょう。ブラウザーの中にはフォームデータの自動検証機能を備えたものもありますが、多くはないので、それには頼らず自前の検証機能を実装すべきです。簡単な例を見てみましょう。

まず、姓と名を入力させる単純な HTML フォームです。

```html
<form>
  <div>
    <label for="fname">姓: </label>
    <input id="fname" type="text" />
  </div>
  <div>
    <label for="lname">名: </label>
    <input id="lname" type="text" />
  </div>
  <div>
    <input id="submit" type="submit" />
  </div>
</form>
<p></p>
```

```
div {
  margin-bottom: 10px;
}
```

 これで JavaScript を少し入れます。ここでは、テキストフィールドが空かどうかをテストする `submit` イベント（フォームを送信すると submit イベントが発生します）のハンドラーの中に、とても単純なチェックを実装します。
 もしそうであれば、イベントオブジェクトの `preventDefault()` 関数を呼び出してフォームの送信を停止し、フォームの下の段落にエラーメッセージを表示して何が間違っているのかをユーザーに指示します。

```js
const form = document.querySelector("form");
const fname = document.getElementById("fname");
const lname = document.getElementById("lname");
const para = document.querySelector("p");

form.addEventListener("submit", (e) => {
  if (fname.value === "" || lname.value === "") {
    e.preventDefault();
    para.textContent = "You need to fill in both names!";
  }
});
```

 明らかに、これはかなり緩いフォーム検証です。例えば、空白や数字が入力されたフォームをユーザーが検証するのを止めることはできませんが、例としては問題ありません。
 出力は以下のようになります。

**メモ:** ソースコード全体については、 preventdefault-validation.html を（およびライブ実行も）ご覧ください。

イベントのバブリング
----------

イベントのバブリングは、ブラウザーが入れ子になった要素を対象とするイベントをどのように処理するかを記述しています。

### 親要素にリスナーを設定

次の様なウェブページがあったとします。

```html
<div id="container">
  <button>クリックしてください</button>
</div>
<pre id="output"></pre>
```

ここではボタンは別の要素 `<div>` の中にあります。ここでは、 `<div>` 要素が、内包する要素の**親**であるといいます。親要素にクリックイベントハンドラーを追加し、ボタンをクリックするとどうなるでしょうか？

```js
const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `${e.currentTarget.tagName} 要素をクリックしました\n`;
}

const container = document.querySelector("#container");
container.addEventListener("click", handleClick);
```

ユーザーがボタンをクリックすると、親がクリックイベントを発生させることがわかります。
```

DIV 要素をクリックしました
```

これは意味があります。ボタンは `<div>` の中にあるので、ボタンをクリックすると、その中にある要素も暗黙のうちにクリックしたことになります。

### バブリングの例

ボタンと親にイベントリスナーを追加したらどうなるでしょうか？

```html
<body>
  <div id="container">
    <button>クリックしてください</button>
  </div>
  <pre id="output"></pre>
</body>
```

ボタンとその親 (`<div>`)、そしてどちらも内包する `<body>` 要素にクリックイベントハンドラーを追加してみましょう。

```js
const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `${e.currentTarget.tagName} 要素をクリックしました\n`;
}

const container = document.querySelector("#container");
const button = document.querySelector("button");

document.body.addEventListener("click", handleClick);
container.addEventListener("click", handleClick);
button.addEventListener("click", handleClick);
```

ユーザーがボタンをクリックすると、 3 つの要素すべてがクリックイベントを発行することがわかります。
```

BUTTON 要素をクリックしました
DIV 要素をクリックしました
BODY 要素をクリックしました
```

この場合、次のようになります。

* 最初にボタン上で click が発生します
* 続いて click が親（`<div>` 要素）で発生します
* 続いて `<div>` 要素の親（`<body>` 要素）で発生します

これを、クリックされた最も内側の要素からイベントが**バブルアップ**すると言います。

この動作は有益なこともあれば、予期せぬ問題を発生させることもあります。次の節では、この動作が発生させる問題を見て、解決策を探ります。

### 動画プレイヤーの例

この例では、最初は非表示になっている動画と、"動画を表示" とラベル付けされたボタンがページに表示されています。私たちは以下のような操作をしたいと思います。

* ユーザーが「動画を表示」ボタンをクリックしたら、動画を格納したボックスを表示させますが、動画の再生はまだ始めません。
* ユーザーが動画をクリックしたら、動画の再生を始めます。
* ユーザーが動画外のボックスのどこかをクリックしたら、ボックスを非表示にします。

HTML は次のようになります。

```html
<button>動画を表示</button>

<div class="hidden">
  <video>
    <source
 src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
 type="video/webm" />
    <p>
      お使いのブラウザーは HTML 動画に対応していません。代わりに<a
 href="rabbit320.mp4"
 >動画へのリンク</a
 >をご利用ください。
    </p>
  </video>
</div>
```

これには以下のものが含まれます。

* `<button>` 要素
* `<div>` 要素、最初は `class="hidden"` 属性つき
* `<video>` 要素（`<div>` 要素の中に入れ子になっている）

`"hidden"` クラスが設定されている要素を非表示にするために CSS を使用しています。
```

div {
  width: 100%;
  height: 100%;
  background-color: #eee;
}

.hidden {
  display: none;
}

div video {
  padding: 40px;
  display: block;
  width: 400px;
  margin: 40px auto;
}
```

JavaScript　はこのようになっています。

```js
const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");

btn.addEventListener("click", () => box.classList.remove("hidden"));
video.addEventListener("click", () => video.play());
box.addEventListener("click", () => box.classList.add("hidden"));
```

これは 3 つの `'click'` イベントリスナーを追加します。

* 一つは `<button>`、これは `<video>` を含んでいる `<div>` を表示します
* 一つは `<video>`、これは動画の再生を開始します
* 一つは `<div>`、これは動画を非表示にします

この動作を確認してみましょう。

ボタンをクリックすると、ボックスとそれを含む動画が表示されます。しかし、次に動画をクリックすると、動画の再生が始まりますが、ボックスは再び非表示になります。

動画は `<div>` の中にあり、その一部です。そのため、動画をクリックすると両方のイベントハンドラーが実行され、この動作が発生します。

### stopPropagation() による問題の修正

 前節で見たように、イベントバブリングは時に問題を引き起こすことがありますが、それを防ぐ方法があります。
 `Event` オブジェクトには `stopPropagation()` と呼ばれる関数があり、イベントハンドラーの中で呼び出されると、イベントが他の要素にバブリングするのを防ぎます。

JavaScript をこのように変更することで、現在の問題を修正することができます。

```js
const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");

btn.addEventListener("click", () => box.classList.remove("hidden"));

video.addEventListener("click", (event) => {
  event.stopPropagation();
  video.play();
});

box.addEventListener("click", () => box.classList.add("hidden"));
```

ここでやっていることはすべて、 `<video>` 要素の `'click'` イベントハンドラーのイベントオブジェクトに対して `stopPropagation()` を呼び出しているだけです。これにより、そのイベントがボックスまで上がってくるのを止めることができます。これで、ボタンと動画の両方をクリックしてみてください。
```

<button>動画を表示</button>

<div class="hidden">
  <video>
    <source
 src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
 type="video/webm" />
    <p>
      お使いのブラウザーは HTML 動画に対応していません。代わりに<a
 href="rabbit320.mp4"
 >動画へのリンク</a
 >をご利用ください。
    </p>
  </video>
</div>
```

```
div {
  width: 100%;
  height: 100%;
  background-color: #eee;
}

.hidden {
  display: none;
}

div video {
  padding: 40px;
  display: block;
  width: 400px;
  margin: 40px auto;
}
```

### イベントのキャプチャ

イベントの伝播の別の形式として、イベントキャプチャがあります。これはイベントバブリングと似ていますが、順序が逆になります。つまり、イベントは対象となる最も内側の要素で最初に発生し、その後、入れ子が浅くなる要素に向けて発生するのではなく、入れ子の最も浅い要素で最初に発生し、その後、対象とする要素に到達するまで、入れ子が深い要素に向けて発生します。

イベントのキャプチャは既定では無効です。有効にするには `addEventListener()` で `capture` オプションを渡す必要があります。

この例は、 `capture` オプションを使用していることを除けば、先ほど見たバブリングの例と同じです。

```html
<body>
  <div id="container">
    <button>クリックしてください</button>
  </div>
  <pre id="output"></pre>
</body>
```

```js
const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `${e.currentTarget.tagName} 要素をクリックしました\n`;
}

const container = document.querySelector("#container");
const button = document.querySelector("button");

document.body.addEventListener("click", handleClick, { capture: true });
container.addEventListener("click", handleClick, { capture: true });
button.addEventListener("click", handleClick);
```

この場合、メッセージの順番は逆になります。 `<body>` のイベントハンドラーが最初に発生し、続いて `<div>` のイベントハンドラーが発生し、続いて `<button>` のイベントハンドラーが発生します。
```

BODY 要素をクリックしました
DIV 要素をクリックしました
BUTTON 要素をクリックしました
```

なぜわざわざキャプチャとバブリングの両方があるのでしょうか？ブラウザー間の互換性が今よりもずっと低かった悪い時代には、ネットスケープはイベントキャプチャのみを使用し、インターネットエクスプローラーはイベントバブリングのみを使用していました。 W3C が動作を標準化し、コンセンサスを得ようと決めたとき、両者を含めるためにこのシステムに行き着き、現代のブラウザーに実装されました。

既定では、ほとんどすべてのイベントハンドラーはバブリングフェーズで登録され、この方がほとんどの場合、意味があります。

イベントの移譲
-------

前回の節では、イベントバブリングによって発生させられる問題と、それを修正する方法について見ていきました。しかし、イベントバブリングは単に煩わしいだけではありません。特に、**イベントの委譲**を可能にします。この方法では、ユーザーが多数の子要素のいずれかを操作したときに何らかのコードを実行したい場合、子要素に個別にイベントリスナーを設定するのではなく、子要素の親要素にイベントリスナーを設定し、子要素で発生したイベントが親要素にバブリングされるようにします。

最初の例に戻り、ユーザーがボタンをクリックしたときにページ全体の背景色を設定しましょう。その代わりに、ページが 16 のタイルに分割されていて、ユーザーがそのタイルをクリックしたときに各タイルにランダムな色を設定したいとします。

これがその HTML です。

```html
<div id="container">
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
</div>
```

タイルのサイズと位置を設定するために、ちょっとした CSS を設けています。

```css
.tile {
  height: 100px;
  width: 25%;
  float: left;
}
```

さて、JavaScript では、すべてのタイルにクリックイベントハンドラーを追加することができます。しかし、よりシンプルで効率的なオプションは、親にクリックイベントハンドラーを設定し、ユーザーがタイルをクリックしたときにハンドラーが確実に実行されるようにイベントバブリングに頼ることです。

```js
function random(number) {
  return Math.floor(Math.random() \* number);
}

function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  return rndCol;
}

const container = document.querySelector("#container");

container.addEventListener("click", (event) => {
  event.target.style.backgroundColor = bgChange();
});
```

出力は次の通りです（クリックしてみてください）。

**メモ:** この例では、 `event.target` を使用して、イベントの対象となった要素（つまり、最も内側の要素）を取得しています。もし、このイベントを処理した要素（この場合はコンテナー）にアクセスしたい場合は、 `event.currentTarget` を使用することができます。

**メモ:** 完全なソースコードは useful-eventtarget.html を参照してください。こちらからライブ実行も確認してください。

ウェブページだけではない
------------

 イベントは JavaScript 固有のものではありません。ほとんどのプログラミング言語には何らかのイベントモデルがあり、そのモデルの動作する方法は JavaScript の方法とは異なることが多いのです。
 実際、ウェブページ用の JavaScript でのイベントモデルは、他の環境で使用する JavaScript のイベントモデルとは異なります。

 例えば、 Node.js はとても人気のある JavaScript ランタイムで、開発者が JavaScript を使用してネットワークやサーバーサイドのアプリケーションを構築することができます。
 Node.js イベントモデルは、イベントを待ち受けするリスナーと、定期的にイベントを発信するエミッターによってできています。それほど異なるものには聞こえませんが、コードはかなり異なり、イベントリスナーを登録するための `on()` や、一度実行した後に登録を解除するイベントリスナーを登録するための `once()` などの関数を使用しています。
 The HTTP connect event docs provide a good example.

 また、 JavaScript を使用し、 WebExtensions と呼ばれる技術を使って、クロスブラウザーのアドオン（ブラウザー機能拡張）を構築することもできます。
 イベントモデルはウェブイベントモデルに似ていますが、少し異なります。イベントリスナーのプロパティはキャメルケース (en-US)で書かれ（`onmessage` ではなく `onMessage` など）、 `addListener` 関数と組み合わせる必要があります。
 例えば、`runtime.onMessage` ページを参照してください。

この段階では、他の環境について何かを理解する必要はありません。プログラミング環境が異なると、イベントが異なる可能性があることを明確にしたかっただけです。

スキルをテストしましょう
------------

この記事の終わりまで到達しましたが、最も大事な情報を覚えていますか？次に行く前に、この情報が身に付いたかどうか確認するには — Test your skills: Events (en-US) を見てください。

まとめ
---

ウェブイベントについて、今の学習初期段階で知るべき事は全部わかったはずです。上で述べたように、実のところイベントは JavaScript のコアには属しません。それらはブラウザーのウェブ API に属するものです。

 また、JavaScript が使用されるさまざまなコンテキストには、異なるイベントモデルがあることを理解することも重要です。ウェブ API から、ブラウザー WebExtensions や Node.js (サーバーサイド JavaScript) など、他にもさまざまな分野があります。
 これでこれらの領域をすべて理解できるとは思っていませんが、ウェブ開発者を学習していく上で、イベントの基本的なことを理解しておくことはとても役に立ちます。

**メモ:** もし行き詰まったら、私たちのコミュニケーションチャンネルのいずれかに連絡してください。

関連情報
----

* domevents.dev — 探索を通して DOM Event システムの動作について学ぶことができる、とても有益なインタラクティブな遊び場アプリです。
* イベントリファレンス
* Event order （キャプチャリングとバブリングについての考察） - Peter-Paul Koch による非常に詳細な記事。
* Event accessing （イベントオブジェクトについての考察）- Peter-Paul Koch によるこれまた素晴らしく詳細な作品。
* 前のページ
* Overview: Building blocks
* 次のページ


アニメーションを順番に再生する - ウェブ開発を学ぶ

アニメーションを順番に再生する
===============

* 前のページ
* Overview: Asynchronous

この評価では、一連のアニメーションを順番に再生するためにページを更新します。これを行うには、プロミスの使い方の記事で学んだテクニックのいくつかを使用します。

|  |  |
| --- | --- |
| 前提条件: | 基本的なコンピューターリテラシー、JavaScript の基本、プロミスベースの API を使用する方法をそれなりに理解していること。 |
| 目標: | プロミスベースの API を使用する方法の理解度をテストするため。 |

開始点
---

https://github.com/mdn/learning-area/tree/main/javascript/asynchronous/sequencing-animations/startにあるファイルのローカルコピーを作成ししてください。 4 つのファイルが含まれています。

* alice.svg
* index.html
* main.js
* style.css

編集するファイルは、 "main.js" だけです。

ブラウザーで "index.html" を開くと、 3 つの画像が斜めに配置されているのがわかるでしょう。

![アニメーションを順番に再生する評価ページのスクリーンショット](/ja/docs/Learn/JavaScript/Asynchronous/Sequencing_animations/sequencing-animations.png)

画像は、ウェブアニメーション API を使用するのガイドから引用しています。

プロジェクト概要
--------

このページを、 3 つの画像すべてにアニメーションを適用し、 1 つずつ順番に更新していくように更新してください。つまり、最初の画像が終了したら 2 つ目の画像を、 2 つ目の画像が終了したら 3 つ目の画像をアニメーションさせるわけです。

このアニメーションは、すでに "main.js" で定義されているもので、画像を回転させ、消えるまで縮小させるだけです。

このページがどのように動作するかをもっと理解してもらうために、完成例を見てください。アニメーションは一度しか実行されないことに注意してください。もう一度実行させたい場合は、ページを再読み込みしてください。

完成までのステップ
---------

### 最初の画像をアニメーションさせる

画像のアニメーションにはウェブアニメーション API を使用しており、具体的には `element.animate()` メソッドを使用しています。

"main.js" を更新して、以下のように `alice1.animate()` の呼び出しを追加してください。

```js
const aliceTumbling = [
  { transform: "rotate(0) scale(1)" },
  { transform: "rotate(360deg) scale(0)" },
];

const aliceTiming = {
  duration: 2000,
  iterations: 1,
  fill: "forwards",
};

const alice1 = document.querySelector("#alice1");
const alice2 = document.querySelector("#alice2");
const alice3 = document.querySelector("#alice3");

alice1.animate(aliceTumbling, aliceTiming);
```

ページを再読み込みすると、最初の画像が回転したり縮小したりするのがわかるはずです。

### すべての画像をアニメーションさせる

次に、`alice1` が終了したら `alice2` を、 `alice2` が終了したら `alice3` をアニメーションさせたいと思います。

`animate()` メソッドは `Animation` オブジェクトを返します。このオブジェクトには `finished` プロパティがあり、これはアニメーションの再生が完了したときに履行される `Promise` です。つまり、次のアニメーションを開始するタイミングを知るために、このプロミスを使用することができます。

この実装を行うためにいくつかの異なる方法を試し、プロミスを使用する方法を強化していただきたいと思います。

1. 最初に、動作するものを実装するのですが、コールバックを使用する際の注意点で見た「コールバック地獄」問題のプロミス版があります
2. 次に、これをプロミス連鎖として実装しましょう。アロー関数で使用できる形が異なるため、この書き方はいくつかあることに注意してください。どれが一番簡潔でしょうか？どれが一番読みやすいと感じますか？
3. 最後に `async` と `await` を使用して実装しましょう。

`element.animate()` は `Promise` を返すのではないことに注意してください。 `Promise` である `finished` プロパティを持つ `Animation` オブジェクトを返すのです。

評価またはさらなる支援
-----------

自分の作品を評価してほしい、または行き詰まりを感じていて相談したい場合は、次のようにしてください。

1. CodePen, jsFiddle, Glitchなどのオンライン共有エディターに自分の作品を入れてください。
2. MDN Discourse forum 学習カテゴリーに評価や助けを依頼する記事を（英語で）書いてください。記事には以下のことを記載してください。
    * "Assessment wanted for Sequencing animations" など、わかりやすいタイトル。
    * すでに試したこと、そして私たちに何をしてほしいかについての詳細（例：行き詰まって助けが必要なとき、または評価が必要なとき）。
    * 評価したい、または助けが必要な例へのリンクを、オンライン共有エディター（上記のステップ 1 で述べたとおり）にて添付してください。コードを見ることができなければ、コーディングの問題で誰かを助けることはとても難しいのです。
    * 実際の課題または評価ページへのリンクで、助けを求めている問題を探すことができます。
* 前のページ
* Overview: Asynchronous