👁

JavaScriptの基本文法

この章では、JavaScriptの基本文法について概要を解説し、ハンズオン形式で実際に動作させながら学習します。これにより、変数・データ型・配列・関数・制御構文など、JavaScriptでコードを書くための基本が身につきます。

1. 本章の概要

1.1 本章の目的

HTML/CSSの基本 で作った画面に、ユーザ操作への反応やサーバとのデータ通信といった動きを加えるのがJavaScriptの役割です。TypeScriptやReact/Next.jsを扱う後続章の土台になるため、ここで基本文法を押さえておくと、以降のフレームワーク学習で「これはJavaScriptの機能」「これはフレームワーク固有」を切り分けやすくなります。

1.2 ハンズオンの流れ

本章では、ブラウザに組み込まれたDevToolsのコンソールで、変数・データ型・配列・オブジェクト・関数・制御構文を1つずつ動かしながら結果を確認して進めます。モジュール(import / export)はNode.jsを扱う後続章、DOM操作やAPI呼び出しは次章 JavaScriptの応用構文 で扱います。

2. JavaScriptとは

2.1 JavaScriptの位置づけ

JavaScriptは、ブラウザ上で動作する唯一のプログラミング言語として広く普及しています。HTMLがWebページの構造、CSSが見た目を担当するのに対し、JavaScriptはWebページの振る舞いを担当します。ボタンをクリックしたときの動作、フォームの入力チェック、外部APIからのデータ取得など、対話的な処理はすべてJavaScriptで書かれています。

💡 ポイント
現在ではNode.jsという実行環境の登場により、ブラウザの外でもJavaScriptを動かせるようになりました。サーバサイドのAPI、ビルドツール、CLIコマンドなど、フロントエンド以外の領域でも幅広く使われています。この講座で主に扱うのはブラウザ側のJavaScriptですが、React(Next.js)を動かすビルドツールもNode.js上で動作するため、後続章でNode.jsを改めて扱います。本章では、ブラウザだけで動作確認を進めます。

2.2 開発環境の準備

JavaScriptには、ほかの言語のように「ローカルにインストールして単体で動かすランタイム」がありません。そのため、ブラウザに組み込まれたJavaScriptエンジンで動かします。本章ではGoogle Chromeの利用を前提とします。Chromeに組み込まれた開発者ツール(DevTools)のコンソール(Console)から、JavaScriptコードを即座に実行できます。本章ではこのコンソールを使い、コードを1つずつ動かしながら結果を確認します。

JavaScriptの特徴であるブラウザ上での利用(HTMLと組み合わせて画面を動かす仕組み)は、次章 JavaScriptの応用構文 で扱います。

以下の手順でコンソールを開きます。

  1. Google Chrome を起動する
  2. 新しいタブで about:blank を開く(アドレスバーに about:blank と入力してEnterキーを押す)

  1. 画面上で右クリック→「検証」を選ぶ(キーボードショートカットで開く場合は、macOSは Command + Option + I、Windowsは F12)
  2. 開いたパネル上部のタブから「Console」を選ぶ

DevTools を初めて開くと、上部に「DevTools is now available in Japanese」という案内が表示される場合があります。日本語表記に切り替えたい場合は「Switch DevTools to Japanese」を、英語のまま進めたい場合は「Don't show again」を押します。本章のスクリーンショットは英語表記のまま進めます。

Console の > の右側にコードを入力してEnterキーを押すと、その場で実行され結果が下に表示されます。試しに、以下のコードを入力してEnterキーを押します。

console.log("Hello, JavaScript");

以下のような実行結果が表示されます。

Hello, JavaScript

console.logで出力した文字列がConsoleに表示されました。その下に表示される < undefinedconsole.log が値を返さないことを示す表記で、コードの動作結果としては気にしなくて構いません。以降のセクションでは、このConsoleにコードを入力して結果を確認します。

📝 コードを貼り付けるときの警告
Chromeでは、DevToolsのコンソールに初めてコードを貼り付けようとすると Don't paste code into the DevTools Console... という警告が表示され、貼り付けがブロックされます。これはSelf-XSS(コンソールを悪用した攻撃)を防ぐためのChromeの安全機能です。教材のサンプルコードを貼り付けて動かすには、警告に従ってコンソールに allow pasting と入力してEnterキーを押します。以降はそのタブで貼り付けが有効になります。
📝 複数行のコードを入力する
if文や関数など複数行のコードを試すときは、行の途中で改行するのに Shift + Enter を押します。単に Enter を押すとその時点で実行されてしまいます。Console の入力欄は改行に合わせて広がるため、複数行をまとめて入力してから最後にEnterキーを押して実行できます。

3. 変数

JavaScriptで値を格納する変数の宣言方法と、変数が有効な範囲(スコープ)を扱います。

💡 ポイント
本章は、プログラミング全般の基本用語(変数・関数・制御構文などの概念)をある程度理解している前提で、「JavaScriptではどう書くか」という文法を中心に簡潔に解説します。プログラミング自体の基本構文をはじめから学びたい場合は、Python講座Go講座 に基礎から解説があります。

3.1 変数と定数

JavaScriptで変数を宣言する方法は、const / let / var の3種類があります。ここでは1つずつ書き方と挙動を確認します。

const

変数に一度入れた値を後から書き換えないようにしたいときは、const定数として宣言します。書き方は以下のとおりです。

const 変数名 = 値;   // 再代入不可の定数

次のコードは、constで名前を定数として宣言し、後から書き換えようとしてエラーになる例です。

const name = "田中太郎";
console.log(name);
name = "鈴木花子";

以下のような実行結果が表示されます。

田中太郎
Uncaught TypeError: Assignment to constant variable.

console.log(name)田中太郎が出力されたあと、再代入した行でTypeErrorが発生しました。

コードを解説します。

const name = "田中太郎";
name = "鈴木花子";

constで宣言した変数には、その後に別の値を代入できません。値そのものが変わらない前提でコードを読めるため、意図しない書き換えを防げます。

let

後から値を書き換える可能性がある変数は、letで宣言します。書き方は以下のとおりです。

let 変数名 = 値;   // 再代入可能な変数

次のコードは、letで年齢を宣言し、後から値を書き換える例です。

let age = 30;
console.log(age);
age = 31;
console.log(age);

以下のような実行結果が表示されます。

30
31

宣言時の30を出力したあと、31に再代入して再度出力しています。

コードを解説します。

let age = 30;
age = 31;

letconstと違い、宣言後に別の値を代入できます。ループのカウンタや状態が変化する値など、書き換えが必要な場面で使います。

var

varは、const / let が導入される前のJavaScriptで使われていた古い変数宣言です。書き方は以下のとおりです。

var 変数名 = 値;   // 古い変数宣言(現代のコードでは使わない)

次のコードは、varで変数を宣言する例です。

var count = 0;
console.log(count);
count = 1;
console.log(count);

以下のような実行結果が表示されます。

0
1

letと同様に再代入できますが、後述するスコープの扱いが異なるため、現代のJavaScriptでは基本的に使いません。

コードを解説します。

var count = 0;

varは関数スコープしか持たず、ブロックを飛び越えて有効になってしまうため、意図しないバグを生みやすい特徴があります。新しく書くコードではconst / letに置き換え、既存コードのvarを見つけてもconst / letにリファクタリングすることが推奨されます。

💡 ポイント
変数宣言は 「まず const、再代入が必要なときだけ letvar は使わない」 が現代の一般的な使い分けです。const を優先するのは、値が途中で変わらない保証があるとコードの追跡が楽になり、意図しない再代入によるバグも防げるためです(配列やオブジェクトの中身は const でも変更できるため、実用上ほとんどの場面で const が使えます)。var を使わないのは、スコープ(変数が有効な範囲)の扱いが異なるためで、const / let{ } で囲まれたブロックスコープiffor の中で宣言した変数はその中でしか参照できない)を持つのに対して、var関数スコープしか持たず、ブロックを飛び越えて有効になり意図しないバグを生みやすいためです。

4. 型

JavaScriptの値が持つ「型」の種類と、型を確認する方法、値の変換や比較の仕組みを扱います。

4.1 プリミティブ型

プリミティブ型は、これ以上分解できない最小単位の値の型です。JavaScriptには以下のプリミティブ型が用意されています。

説明
number 整数と小数を区別せずに数値を扱う 42, 3.14, -1
string 文字列を扱う "hello", 'world'
boolean 真偽値を扱う true, false
null 値が存在しないことを明示的に示す null
undefined 値が代入されていない状態を表す undefined
symbol 一意な識別子を生成する Symbol("id")
bigint 巨大な整数を扱う 9007199254740992n

このうち、日常的に使うのはnumber / string / boolean / null / undefinedの5つです。以降でそれぞれの型を1つずつ確認します。symbolbigintは特殊な用途向けで、初学時点では意識しなくて構いません。

number

整数や小数を扱いたいときは、number型の値を使います。JavaScriptでは整数と小数を型として区別せず、どちらも同じnumberとして扱えます。書き方は以下のとおりです。

const 変数名 = 数値;   // 整数と小数はどちらもnumber型

次のコードは、整数と小数のnumberをそれぞれ宣言して出力する例です。

const count = 10;
const price = 3.14;

console.log(count);
console.log(price);

以下のような実行結果が表示されます。

10
3.14

整数の10と小数の3.14がそのまま出力されました。

コードを解説します。

const count = 10;
const price = 3.14;

JavaScriptでは整数と小数を型として区別しません。演算も+ / - / * / / / %の記号で、整数・小数を混在させて計算できます。

string

文字列を扱いたいときは、string型の値を使います。書き方は以下のとおりです。

const 変数名 = "文字列";   // ダブルクォート または シングルクォートで囲む

次のコードは、stringの値を宣言して出力する例です。

const title = "JavaScript入門";
const message = 'こんにちは';

console.log(title);
console.log(message);

以下のような実行結果が表示されます。

JavaScript入門
こんにちは

ダブルクォートとシングルクォートのどちらで囲んでもstringとして扱われます。

コードを解説します。

const title = "JavaScript入門";
const message = 'こんにちは';

"..."'...'のどちらを使うかは表記の統一の話で、動作に違いはありません。プロジェクト内では片方に統一するのが一般的です。

boolean

真偽値(true / false)を扱いたいときは、boolean型の値を使います。書き方は以下のとおりです。

const 変数名 = true;   // true または false

次のコードは、booleanの値を宣言して出力する例です。

const isPublished = true;
const isDraft = false;

console.log(isPublished);
console.log(isDraft);

以下のような実行結果が表示されます。

true
false

truefalseの2値のみを取ります。

コードを解説します。

const isPublished = true;

if文の条件式や真偽値を返す関数の戻り値など、フラグとして値を扱う場面で使います。

null

「値が存在しない」ことをコード上で明示したいときは、nullを使います。書き方は以下のとおりです。

const 変数名 = null;   // 値が存在しないことを明示する

次のコードは、nullを代入して出力する例です。

const empty = null;
console.log(empty);

以下のような実行結果が表示されます。

null

empty変数にnullが代入され、そのまま出力されました。

コードを解説します。

const empty = null;

「値がまだ決まっていない」「意図的に空の状態にする」といった表現に使います。次に紹介するundefinedと似ていますが、nullは「開発者が意図して空にした値」というニュアンスがあります。

undefined

変数を宣言しただけで値をまだ入れていない状態を表すのが、undefinedです。書き方は以下のとおりです。

let 変数名;   // 値を代入せずに宣言すると、自動的にundefinedになる

次のコードは、宣言だけして値を代入しなかった変数を出力する例です。

let notAssigned;
console.log(notAssigned);

以下のような実行結果が表示されます。

undefined

代入していないため、変数の値はundefinedとして出力されました。

コードを解説します。

let notAssigned;

宣言時に値を指定しない変数は、自動的にundefinedになります。関数が明示的に値を返さない場合の戻り値もundefinedです。nullが「意図して空にした」ニュアンスなのに対し、undefinedは「まだ何も入っていない」ニュアンスがあります。

symbol と bigint

symbolは一意な識別子を生成する型で、ライブラリ内部でオブジェクトのキーが衝突しないようにするなど、特殊な用途で使います。bigintnumberの範囲を超える巨大な整数(2^53超)を扱うための型です。

いずれも実務で頻繁に登場する型ではないため、本章では紹介にとどめ、必要な場面で改めて詳しく学びます。

typeofによる型確認

変数の型を実行時に調べたいときは、typeof演算子を使います。書き方は以下のとおりです。

typeof 値;   // 値の型を文字列で返す("number" / "string" / "boolean" / "undefined" / "object" など)

次のコードは、代表的な値に対してtypeofを適用し、型名を確認する例です。

console.log(typeof 42);
console.log(typeof "hello");
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);

以下のような実行結果が表示されます。

number
string
boolean
undefined
object

数値・文字列・真偽値・undefinedはそのまま型名が返る一方、null"object"が返りました。

コードを解説します。

console.log(typeof null);

typeof null"object"と返る点は、言語仕様の初期から残っている歴史的な挙動です。nullかどうかを判定したい場合はtypeofではなくvalue === nullのように直接比較します。

4.2 テンプレートリテラル

文字列の中に変数の値や式を埋め込みたいときは、バッククォート(`)で囲むテンプレートリテラルを使います。ここでは変数の埋め込みと複数行の文字列の2パターンを扱います。

変数の埋め込み

文字列の中に変数の値を埋め込みたいときは、バッククォート内に ${変数名} の形で書きます。書き方は以下のとおりです。

`文字列の途中に${変数や式}を埋め込める`;   // ${}の中には変数だけでなく式も書ける

次のコードは、名前と年齢の変数をテンプレートリテラルで文字列に埋め込む例です。

const name = "田中太郎";
const age = 30;

const message = `${name}さんは${age}歳です。`;
console.log(message);

以下のような実行結果が表示されます。

田中太郎さんは30歳です。

${name}${age}の位置に、変数の値がそのまま埋め込まれた文字列が出力されました。

コードを解説します。

const message = `${name}さんは${age}歳です。`;

${}の中には変数だけでなく、${age + 1}のような式も書けます。文字列連結の+を使うより読みやすくなるため、変数を含む文字列は基本的にテンプレートリテラルで書きます。

複数行の文字列

複数行にわたる文字列をそのまま書きたいときは、テンプレートリテラル内で改行します。書き方は以下のとおりです。

`1行目
2行目
3行目`;   // 改行がそのまま文字列に含まれる

次のコードは、複数行の文字列を宣言して出力する例です。

const text = `1行目
2行目
3行目`;

console.log(text);

以下のような実行結果が表示されます。

1行目
2行目
3行目

バッククォート内の改行がそのまま文字列に反映されました。

コードを解説します。

const text = `1行目
2行目
3行目`;

シングルクォート・ダブルクォートの文字列では\nのようなエスケープ文字が必要ですが、テンプレートリテラルではエディタで書いた改行がそのまま文字列に含まれます。長いメッセージやHTMLテンプレートなど、複数行の文字列を扱う場面で便利です。

4.3 真偽値変換とfalsy値

if文などで真偽値が期待される場所に他の型の値を渡すと、自動的に真偽値に変換されます。このときfalse扱いになる値をfalsy(フォルシー)値と呼び、以下の値が該当します。

  • false
  • 0
  • ""(空文字列)
  • null
  • undefined
  • NaN

これ以外の値はすべてtrue扱い(truthy)です。空の配列[]や空のオブジェクト{}もtruthyになる点は間違いやすいので注意します。

次のコードは、0と空配列・空オブジェクトをifの条件に渡し、falsy / truthy の判定を確認する例です。

if (0) {
  console.log("0はtrue");
} else {
  console.log("0はfalse扱い");
}

if ([]) {
  console.log("空配列はtrue扱い");
}

if ({}) {
  console.log("空オブジェクトはtrue扱い");
}

以下のような実行結果が表示されます。

0はfalse扱い
空配列はtrue扱い
空オブジェクトはtrue扱い

0は falsy としてelse側に流れ、中身が空の配列とオブジェクトは truthy としてif側に流れました。

コードを解説します。

if ([]) {
  console.log("空配列はtrue扱い");
}

[]は要素が0個でもオブジェクトの一種として存在する値のため、truthy扱いになります。配列の中身が空かどうかはarray.length === 0のように長さで判定します。

4.4 等価比較

2つの値が等しいかを比較したいときは、===を使います。JavaScriptには=====の2種類の比較演算子があり、==は暗黙の型変換を伴う比較、===は型を含めた厳密比較です。書き方は以下のとおりです。

1 == 値2;    // 型変換したうえで一致するかを比較する(暗黙の型変換あり)1 === 値2;   // 型と値の両方が一致するかを比較する(型変換なし・厳密比較)

次のコードは、=====の挙動の違いを確認する例です。

console.log(1 == "1");
console.log(1 === "1");
console.log(null == undefined);
console.log(null === undefined);

以下のような実行結果が表示されます。

true
false
true
false

==は型が違っても暗黙変換して比較する一方で、===は型が違えば必ずfalseを返しました。

コードを解説します。

console.log(1 == "1");
console.log(1 === "1");

==は左辺と右辺を同じ型に揃えてから比較するため、1 == "1"trueになります。===は型と値の両方を比較するため、1(number)と"1"(string)は別物としてfalseが返ります。

==は暗黙の型変換が絡み予測しにくい挙動になるため、実際には常に===を使うのが基本です。ESLintなどの静的解析ツールでも==は警告対象になることが多く、意図しないバグを避けるためにも===を使う習慣をつけておきます。

5. 制御構文

条件分岐と繰り返しの構文を扱います。

5.1 条件分岐

if / else、三項演算子、switchの3種類を扱います。

if / else

条件によって処理を分岐させたいときは、if / else if / elseで書きます。書き方は以下のとおりです。

if (条件式) {
  条件がtrueのときの処理;
} else if (別の条件式) {
  別の条件がtrueのときの処理;
} else {
  どの条件も満たさなかったときの処理;
}

次のコードは、点数を段階的に判定して該当する評価を出力する例です。

const score = 75;

if (score >= 80) {
  console.log("優");
} else if (score >= 60) {
  console.log("良");
} else {
  console.log("要努力");
}

以下のような実行結果が表示されます。

7580未満のためifのブロックはスキップされ、else ifの条件60以上を満たしたためが出力されました。

コードを解説します。

if (score >= 80) {
  console.log("優");
} else if (score >= 60) {
  console.log("良");
} else {
  console.log("要努力");
}

条件式には比較演算子(> / < / ===など)や論理演算子(&& / || / !)を組み合わせて書きます。ifから順に評価され、最初にtrueになったブロックだけが実行されます。

三項演算子

シンプルな条件分岐を1行で書きたいときは、三項演算子を使います。書き方は以下のとおりです。

const 結果 = 条件 ? 真のときの値 : 偽のときの値;   // 条件がtrueなら左、falseなら右の値を返す

次のコードは、年齢が18以上かどうかで表示ラベルを切り替える例です。

const age = 20;
const label = age >= 18 ? "成人" : "未成年";

console.log(label);

以下のような実行結果が表示されます。

成人

age >= 18trueとなり、成人labelに代入されました。

コードを解説します。

const label = age >= 18 ? "成人" : "未成年";

条件 ? 真のときの値 : 偽のときの値という形式で、式全体が値を返すためconstへの代入や関数の戻り値に使えます。React JSX内で表示を出し分けする際にも頻繁に使います。

switch

1つの値に対する複数分岐を整理して書きたいときは、switch文を使います。書き方は以下のとおりです。

switch (対象の値) {
  case1:
    値1のときの処理;
    break;   // caseを抜けるためのbreakを忘れない
  case2:
    値2のときの処理;
    break;
  default:
    どのcaseにも一致しなかったときの処理;
}

次のコードは、statusの値に応じて表示メッセージを切り替える例です。

const status = "loading";

switch (status) {
  case "idle":
    console.log("待機中");
    break;
  case "loading":
    console.log("読み込み中");
    break;
  case "success":
    console.log("完了");
    break;
  default:
    console.log("不明な状態");
}

以下のような実行結果が表示されます。

読み込み中

statusloadingと一致したcaseのブロックだけが実行されました。

コードを解説します。

case "loading":
  console.log("読み込み中");
  break;

caseの最後には必ずbreakを書きます。breakを忘れると次のcaseまで処理が続いてしまう「フォールスルー」と呼ばれる挙動になり、意図しないバグの原因になります。

5.2 繰り返し

for / for-of / for-in / whileの4種類を扱います。

for

回数を指定した繰り返しを書きたいときは、伝統的なC言語系のfor文を使います。書き方は以下のとおりです。

for (初期化式; 継続条件; 更新式) {
  繰り返し実行する処理;
}

次のコードは、0から2までの数値を順に出力する例です。

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

以下のような実行結果が表示されます。

0
1
2

初期化でi = 0とし、i < 3の条件を満たす間、i++で1ずつ増やしながら本体を繰り返しました。

コードを解説します。

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

3つのパートは、初期化式・継続条件・更新式に対応します。最も自由度の高いループ構文ですが、配列を回すだけなら次のfor-ofのほうが読みやすくなります。

for-of

配列やイテラブルオブジェクトのを順に取り出したいときは、for-ofを使います。書き方は以下のとおりです。

for (const 変数 of 配列) {
  変数を使った処理;
}

次のコードは、配列の各要素を順に取り出して出力する例です。

const fruits = ["apple", "banana", "cherry"];

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

以下のような実行結果が表示されます。

apple
banana
cherry

fruitsの要素が先頭から順にfruitに代入され、そのたびに出力されました。

コードを解説します。

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

インデックスの管理が不要なため、値だけを使いたい場面ではforより簡潔に書けます。文字列やSetなど、他のイテラブルにも同じ書き方で使えます。

for-in

オブジェクトのキーを順に取り出したいときは、for-inを使います。書き方は以下のとおりです。

for (const キー in オブジェクト) {
  キーとオブジェクト[キー]を使った処理;
}

次のコードは、オブジェクトのキーと値を順に出力する例です。

const user = { id: 1, name: "田中太郎", email: "tanaka@example.com" };

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}

以下のような実行結果が表示されます。

id: 1
name: 田中太郎
email: tanaka@example.com

userの各キーがkeyに順に代入され、user[key]で対応する値を取り出せました。

コードを解説します。

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}

for-inが回すのはキーそのもので、値を得るにはuser[key]のようにブラケット記法で参照します。配列に対しても使えますが、インデックスが文字列として得られるなど落とし穴があるため、配列はfor-ofを使うのが安全です。

while

条件を満たす間だけ処理を繰り返したいときは、whileを使います。書き方は以下のとおりです。

while (継続条件) {
  条件がtrueである間、繰り返し実行する処理;
}

次のコードは、countが3になるまで値を出力し続ける例です。

let count = 0;

while (count < 3) {
  console.log(count);
  count++;
}

以下のような実行結果が表示されます。

0
1
2

count3に達した時点で条件がfalseになり、ループが終了しました。

コードを解説します。

while (count < 3) {
  console.log(count);
  count++;
}

ループを終わらせる責任は本体側にあります。count++のような更新処理を忘れると条件がずっとtrueのままになり、無限ループの原因になります。

6. 関数

まとまった処理に名前を付けて再利用するための関数を扱います。基本の宣言方法から、簡潔な書き方のアロー関数、引数のバリエーション、関数を値として渡すコールバック関数高階関数まで順に扱います。

6.1 関数宣言

まとまった処理に名前を付けて再利用したいときは、functionキーワードで関数を宣言します。書き方は以下のとおりです。

function 関数名(引数1, 引数2) {
  処理;
  return 戻り値;   // 値を返す場合はreturnを使う
}
関数名(引数);   // 呼び出す

次のコードは、名前を受け取って挨拶文を返す関数を宣言して呼び出す例です。

function greet(name) {
  return `こんにちは、${name}さん`;
}

console.log(greet("田中"));

以下のような実行結果が表示されます。

こんにちは、田中さん

greet("田中")の呼び出しで、引数name田中が渡り、テンプレートリテラルで作られた文字列が戻り値として返りました。

コードを解説します。

function greet(name) {
  return `こんにちは、${name}さん`;
}

functionキーワードに続けて関数名、引数、処理本体を書きます。値を返す場合はreturn文を使い、呼び出し側では戻り値を変数に受け取ったり、そのまま他の式で利用したりできます。

6.2 関数式

関数そのものを値として変数に代入したいときは、関数式の書き方を使います。書き方は以下のとおりです。

const 変数名 = function (引数) { 処理; return 戻り値; };   // 関数を値として変数に代入する

次のコードは、関数式で挨拶関数を定義する例です。

const greet = function (name) {
  return `こんにちは、${name}さん`;
};

console.log(greet("鈴木"));

以下のような実行結果が表示されます。

こんにちは、鈴木さん

関数宣言と同じ結果ですが、関数を値として変数に代入している点が特徴です。

コードを解説します。

const greet = function (name) {
  return `こんにちは、${name}さん`;
};

関数式ではfunctionの後に関数名を書かないことが多く、これを無名関数と呼びます。変数に代入する形なので、他の関数の引数として渡す、配列に格納する、といった扱いも自然にできます。

6.3 アロー関数

関数式をより簡潔に書きたいときは、ES2015で導入されたアロー関数を使います。書き方は以下のとおりです。

const 変数名 = (引数) => { 処理; return 戻り値; };   // 基本形(波括弧あり)
const 変数名 = (引数) => 戻り値の式;                 // 処理が式1つだけなら省略形

次のコードは、アロー関数の省略形で挨拶関数と2倍関数をそれぞれ定義する例です。

const greet = (name) => `こんにちは、${name}さん`;
const double = (n) => n * 2;

console.log(greet("佐藤"));
console.log(double(5));

以下のような実行結果が表示されます。

こんにちは、佐藤さん
10

functionキーワードの代わりに=>を使うことで、関数式より短く書けています。処理が1つの式だけのため、波括弧とreturnを省略した省略形になっています。

コードを解説します。

const greet = (name) => `こんにちは、${name}さん`;
const double = (n) => n * 2;

処理が1つの式だけの場合は、波括弧とreturnを省略できます。現代のJavaScriptでは、コールバック関数や短い処理を書く場面ではアロー関数が主流で、ReactのイベントハンドラやReact Hooksの引数もほとんどアロー関数で書きます。

6.4 デフォルト引数

関数の引数を省略できるようにしたいときは、引数にデフォルト値を指定します。書き方は以下のとおりです。

const 関数名 = (引数 = デフォルト値) => 処理;   // 呼び出し時に引数を省略するとデフォルト値が使われる

次のコードは、引数を省略したときにゲストが使われる関数を定義する例です。

const greet = (name = "ゲスト") => `こんにちは、${name}さん`;

console.log(greet("田中"));
console.log(greet());

以下のような実行結果が表示されます。

こんにちは、田中さん
こんにちは、ゲストさん

引数を渡した場合はその値が、渡さなかった場合はデフォルトのゲストが使われました。

コードを解説します。

const greet = (name = "ゲスト") => `こんにちは、${name}さん`;

= "ゲスト"が引数のデフォルト値で、呼び出し時に引数を省略した場合やundefinedを渡した場合に適用されます。関数の呼び出し方に幅を持たせられるので、オプション設定の受け取りなどで便利です。

6.5 可変長引数

呼び出しごとに引数の数が変わる関数を書きたいときは、残余引数(rest parameters)と呼ばれる...構文を使います。書き方は以下のとおりです。

const 関数名 = (...引数の配列) => 処理;   // 渡された引数がすべて配列としてまとめて受け取れる

次のコードは、任意の数の数値を受け取って合計を返す関数を定義する例です。

const sum = (...numbers) => {
  return numbers.reduce((acc, n) => acc + n, 0);
};

console.log(sum(1, 2, 3));
console.log(sum(1, 2, 3, 4, 5));

以下のような実行結果が表示されます。

6
15

呼び出し時の引数がすべてnumbers配列に集約され、reduceで合計が算出されました。

コードを解説します。

const sum = (...numbers) => {
  return numbers.reduce((acc, n) => acc + n, 0);
};

...numbersと書くことで、渡された引数がすべて配列としてまとめて受け取れます。呼び出し側の引数の数を変えられるため、汎用的なユーティリティ関数を書くときに便利です。

6.6 コールバック関数

「あとで実行したい処理」を関数として引数に渡す形式を、コールバック関数と呼びます。書き方は以下のとおりです。

関数((引数) => 処理);   // 関数そのものを引数として渡す

次のコードは、setTimeoutにコールバック関数を渡して、1秒後に実行する例です。

setTimeout(() => {
  console.log("1秒経過しました");
}, 1000);

以下のような実行結果が、1秒後に表示されます。

1秒経過しました

setTimeoutが指定時間(1000ミリ秒)経過後にコールバック関数を実行しました。

コードを解説します。

setTimeout(() => {
  console.log("1秒経過しました");
}, 1000);

setTimeoutの第1引数として関数そのものを渡しています。渡された関数はsetTimeout側で保管され、指定時間経過後に呼び出されます。ボタンクリックやAPIレスポンス受信など、「あとで実行する処理」を関数として渡す書き方は、JavaScriptで頻繁に登場します。

6.7 高階関数

関数を引数として受け取ったり、戻り値として返したりする関数を高階関数と呼びます。先ほど紹介したsetTimeoutもコールバック関数を引数に受け取る高階関数の1つで、後の「配列」節で扱う map / filter / reduce もすべて高階関数です。書き方は以下のとおりです。

const 高階関数 = (値, 関数) => 関数(値);   // 引数として受け取った関数を、内部で呼び出す

次のコードは、加算と乗算の関数を切り替えながら同じ枠組みで適用する例です。

const applyOperation = (a, b, operation) => operation(a, b);

const add = (x, y) => x + y;
const multiply = (x, y) => x * y;

console.log(applyOperation(3, 4, add));
console.log(applyOperation(3, 4, multiply));

以下のような実行結果が表示されます。

7
12

同じ applyOperation(3, 4, ...) の呼び出しでも、渡した関数によって加算(7)と乗算(12)の異なる結果が得られました。

コードを解説します。

const applyOperation = (a, b, operation) => operation(a, b);
console.log(applyOperation(3, 4, add));
console.log(applyOperation(3, 4, multiply));

applyOperation は「2つの値と、それらに適用する関数」を受け取って呼び出す高階関数です。処理の中身(加算・乗算・その他)を関数として外から差し替えられるため、汎用的な部品として使えます。後の「配列」節で扱う map / filter / reduce もこの仕組みで動いており、渡された関数によって「変換」「絞り込み」「集約」の中身が決まります。

7. 配列とオブジェクト

複数の値をまとめて扱うためのデータ構造として、順序付きの配列とキーと値のペアのオブジェクトを扱います。

7.1 配列

配列の作り方(配列リテラル)と、日常的によく使う代表的なメソッドを1つずつ確認します。

配列リテラル

複数の値を順序付きでまとめて扱いたいときは、[]で囲む配列を使います。書き方は以下のとおりです。

const 配列名 = [値1, 値2, 値3];   // カンマ区切りで並べて作成する
配列名[インデックス];   // 0から始まるインデックスで要素を取り出す
配列名.length;   // 要素数を取得する

次のコードは、文字列の配列を作り、先頭要素と長さを取り出す例です。

const fruits = ["apple", "banana", "cherry"];

console.log(fruits[0]);
console.log(fruits.length);

以下のような実行結果が表示されます。

apple
3

fruits[0]で先頭のappleが、fruits.lengthで要素数の3が取得できました。

コードを解説します。

console.log(fruits[0]);
console.log(fruits.length);

要素へのアクセスはfruits[0]のようにインデックス指定で行い、長さはfruits.lengthで取得できます。インデックスは0から始まる点に注意します。

push

配列の末尾に要素を追加したいときは、pushメソッドを使います。書き方は以下のとおりです。

配列名.push(値);   // 末尾に要素を追加する(元の配列を変更する)

次のコードは、配列に要素を追加する例です。

const stack = [1, 2, 3];
stack.push(4);
console.log(stack);

以下のような実行結果が表示されます。

[1, 2, 3, 4]

末尾に4が追加され、要素数が4件になりました。

コードを解説します。

stack.push(4);

pushは配列そのものを直接変更する破壊的なメソッドです。呼び出すたびに元の配列が変わる点に注意します。

pop

配列の末尾から要素を取り出したいときは、popメソッドを使います。書き方は以下のとおりです。

const 取り出した値 = 配列名.pop();   // 末尾の要素を取り出して返す(元の配列も変更する)

次のコードは、配列の末尾から要素を取り出す例です。

const stack = [1, 2, 3];
const last = stack.pop();

console.log(last);
console.log(stack);

以下のような実行結果が表示されます。

3
[1, 2]

popで末尾の3が戻り値として返され、元の配列は[1, 2]に縮みました。

コードを解説します。

const last = stack.pop();

poppushと同じく破壊的なメソッドで、戻り値として取り出した要素を返します。スタック(LIFO)として配列を扱うときにpushとペアで使います。

map

配列の各要素をまとめて別の値に変換したいときは、mapメソッドを使います。元の配列は変更せず、変換後の値を集めた新しい配列を返します。書き方は以下のとおりです。

const 新しい配列 = 元の配列.map((要素) => 変換後の値);   // 各要素を変換した結果を集めた新しい配列を返す

次のコードは、数値の配列を2倍した新しい配列を作る例です。

const numbers = [1, 2, 3, 4];
const doubled = numbers.map((n) => n * 2);

console.log(doubled);
console.log(numbers);

以下のような実行結果が表示されます。

[2, 4, 6, 8]
[1, 2, 3, 4]

各要素が2倍された新しい配列doubledが生成され、元のnumbersは書き換わっていません。

コードを解説します。

const doubled = numbers.map((n) => n * 2);

コールバックは要素1つを受け取り、変換後の値を返す関数を渡します。mappushpopと異なり非破壊的で、元の配列を変更せずに新しい配列を返します。Reactでは配列からJSX要素のリストを生成する際にmapを多用するため、慣れておくと後の学習が楽になります。

filter

配列から条件に合う要素だけを取り出したいときは、filterメソッドを使います。条件を満たす要素だけを集めた新しい配列を返します。書き方は以下のとおりです。

const 新しい配列 = 元の配列.filter((要素) => 条件式);   // 条件式がtrueの要素だけを集めた新しい配列を返す

次のコードは、偶数の要素だけを取り出す例です。

const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter((n) => n % 2 === 0);

console.log(evens);

以下のような実行結果が表示されます。

[2, 4]

n % 2 === 0trueになる要素のみが残り、偶数だけの配列が得られました。

コードを解説します。

const evens = numbers.filter((n) => n % 2 === 0);

コールバックは条件式を返す関数で、戻り値がtrueなら残す、falseなら除外する動作をします。mapと同様に非破壊的で、元の配列は変更されません。

reduce

配列の各要素を順に処理して単一の値にまとめたいときは、reduceメソッドを使います。書き方は以下のとおりです。

const 集約結果 = 元の配列.reduce((累積値, 要素) => 次の累積値, 初期値);   // 第2引数の初期値から開始し、各要素で累積値を更新する

次のコードは、数値の配列を合計する例です。

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, n) => acc + n, 0);

console.log(sum);

以下のような実行結果が表示されます。

10

0から始めて1 / 2 / 3 / 4を順に加算した結果、合計値の10が得られました。

コードを解説します。

const sum = numbers.reduce((acc, n) => acc + n, 0);

accは「累積値」を意味するaccumulatorの略で、前回の処理結果が次の呼び出しに渡されます。第2引数の0が最初のaccの値で、各要素が加算されて最終的な合計になります。

find

配列から条件を満たす要素を1つだけ取り出したいときは、findメソッドを使います。条件を最初に満たした要素が1つ返り、見つからなかった場合はundefinedが返ります。書き方は以下のとおりです。

const 要素 = 元の配列.find((要素) => 条件式);   // 条件式が最初にtrueになった要素を返す(見つからなければundefined)

次のコードは、ユーザ配列から特定のIDを持つ要素を1つ取り出す例です。

const users = [
  { id: 1, name: "田中" },
  { id: 2, name: "鈴木" },
  { id: 3, name: "佐藤" },
];

const found = users.find((user) => user.id === 2);
console.log(found);

以下のような実行結果が表示されます。

{id: 2, name: '鈴木'}

id2の要素が最初に見つかり、そのオブジェクト全体が戻り値として返されました。

コードを解説します。

const found = users.find((user) => user.id === 2);

filterは配列を返しますが、findは最初に見つかった要素そのものを返します。1件しかヒットしないと分かっている場面や、条件に合う最初の1件だけが必要な場面で使います。

7.2 オブジェクト

オブジェクトの作り方(オブジェクトリテラル)と、値の取り出し・更新を効率化する分割代入・スプレッド構文を扱います。

オブジェクトリテラル

キーと値のペアでデータを表現したいときは、{}で囲むオブジェクトを使います。書き方は以下のとおりです。

const オブジェクト名 = { キー1: 値1, キー2: 値2 };   // カンマ区切りでキーと値のペアを並べる
オブジェクト名.キー名;      // ドット記法でプロパティにアクセスする
オブジェクト名["キー名"];   // ブラケット記法でプロパティにアクセスする

次のコードは、ユーザ情報を持つオブジェクトを作り、プロパティをドット記法とブラケット記法で読み出す例です。

const user = {
  id: 1,
  name: "田中太郎",
  email: "tanaka@example.com",
};

console.log(user.name);
console.log(user["email"]);

以下のような実行結果が表示されます。

田中太郎
tanaka@example.com

user.nameuser["email"]のどちらもオブジェクトのプロパティを取り出せました。

コードを解説します。

console.log(user.name);
console.log(user["email"]);

プロパティへのアクセスはuser.nameのドット記法と、user["email"]のブラケット記法の2種類があります。キー名が変数で動的に決まる場合はブラケット記法を使います。オブジェクトの中に配列やオブジェクトを入れ子にすることもでき、JSON形式のデータをそのまま表現できます。

分割代入

配列やオブジェクトから必要な値を一度に取り出したいときは、分割代入を使います。書き方は以下のとおりです。

const [変数1, 変数2] = 配列;   // 配列の先頭から順に取り出す
const { キー1, キー2 } = オブジェクト;   // オブジェクトからキー名で取り出す

次のコードは、オブジェクトから必要なプロパティだけを一度に取り出す例です。

const user = { id: 1, name: "田中太郎", email: "tanaka@example.com" };
const { name, email } = user;

console.log(name);
console.log(email);

以下のような実行結果が表示されます。

田中太郎
tanaka@example.com

user.nameuser.emailが変数name / emailにそれぞれ代入されました。

コードを解説します。

const { name, email } = user;

{ }内に列挙したキー名が、オブジェクト側の同名プロパティと対応付いて代入されます。Reactコンポーネントでpropsから必要なプロパティだけを取り出す場面で頻繁に登場するため、書き方に慣れておきます。配列の場合はconst [first, second] = arrayのように[]で書きます。

スプレッド構文

配列やオブジェクトの中身を展開して、別の配列・オブジェクトに取り込みたいときは、スプレッド構文(...)を使います。書き方は以下のとおりです。

const 新しい配列 = [...元の配列, 追加要素];             // 元の配列を展開し、要素を追加できる
const 新しいオブジェクト = { ...元のオブジェクト, キー: 新しい値 };   // 元のオブジェクトを展開し、指定キーだけ上書きできる

次のコードは、オブジェクトの一部プロパティだけを更新した新しいオブジェクトを作る例です。

const user = { id: 1, name: "田中太郎", email: "tanaka@example.com" };
const updated = { ...user, email: "new@example.com" };

console.log(updated);

以下のような実行結果が表示されます。

{id: 1, name: '田中太郎', email: 'new@example.com'}

idnameは元のまま残り、emailだけが新しい値に差し替わった新しいオブジェクトが得られました。

コードを解説します。

const updated = { ...user, email: "new@example.com" };

...userで元のオブジェクトを展開し、その後にemailを上書きすることで、元のオブジェクトを変更せずに新しいオブジェクトを作れます。Reactでは状態を更新する際にこの書き方を多用します。配列の場合は[...a, ...b]で連結や、[...a]でコピーが作れます。

💡 ポイント
JavaScriptにはECMAScript(エクマスクリプト)という言語仕様の標準規格があります。ブラウザやNode.jsは、このECMAScriptの仕様に準拠してJavaScriptエンジンを実装しています。仕様は毎年更新されており、2015年に大きな改訂が入った版をES2015(旧称ES6)と呼びます。本章で扱った const / let、アロー関数、テンプレートリテラルなどは、いずれもES2015以降で導入された文法です。現代のWeb開発ではES2015以降の記法で書くのが標準で、古いブラウザとの互換性を気にする場面ではTypeScriptやBabelといったツールが古い記法に変換してくれるため、書き手はモダンな記法だけを覚えれば足ります。

8. まとめ

この章では、JavaScriptの基本文法を学びつつ、実際にブラウザのコンソールでコードを動かして結果を体験しました。

  • JavaScriptはブラウザ上で動作するプログラミング言語で、ECMAScriptの仕様に準拠している
  • 変数は const を基本とし、再代入が必要なときのみ let を使う(var は使わない)
  • プリミティブ型は number / string / boolean / null / undefined が中心で、typeof で型を確認できる
  • テンプレートリテラル(` + ${変数})により、文字列に値を埋め込める
  • 比較は、暗黙の型変換を伴わない === を常に使う
  • 配列は map / filter / reduce / find などのメソッドチェーンで宣言的に処理できる
  • オブジェクトは、分割代入とスプレッド構文で扱いやすくなる
  • 関数はアロー関数が主流で、コールバック・高階関数と組み合わせて使う

次の章では、JavaScriptの応用構文を学びつつ、実際にDOM操作・API呼び出し・問い合わせフォームの実装を体験します。

この教材は役に立ちましたか?

いいねをたくさんいただけると、制作者の励みになり、より多くのセクションが作れるようになります。

感想を一言(任意)

いただいたコメントは次の制作のヒントになります。ぜひお気軽にご投稿ください。

このコメントは他の受講生には公開されません。DevOps Camp運営が、教材改善のために確認します。

0 / 2000