JavaScript

JavaScript入門

Webページを動かしながら、JavaScriptの基礎を一つずつ学びましょう。

この講座は、現在の主要なモダンブラウザーを対象にしています。

01

JavaScriptとは

JavaScriptは、Webページへ動きや機能を加えられるプログラミング言語です。HTMLがページの構造、CSSが見た目を担当し、JavaScriptは利用者の操作に応じて内容を変更します。

JavaScriptでできること
  • ボタンやメニューをクリックしたときの表示切り替え
  • フォームへ入力された値の確認
  • 画像ギャラリーやアニメーションの制御
  • サーバーからデータを取得して画面を更新
  • ブラウザーへの簡単なデータ保存

JavaScriptはブラウザーだけでなくNode.jsなどでも動きます。この講座では、まずブラウザー上でHTMLを操作するJavaScriptを学びます。

HTMLで構造を作るCSSで見た目を整えるJavaScriptで動かす
02

JavaScriptを実行してみよう

同じフォルダーに index.htmlapp.js を作ります。HTMLからJavaScriptファイルを読み込み、開発者ツールのコンソールへ文字を表示してみましょう。

index.htmlHTML
<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScriptの練習</title>
    <script src="app.js" defer></script>
</head>
<body>
    <h1>JavaScriptの練習</h1>
</body>
</html>
app.jsJAVASCRIPT
console.log('こんにちは、JavaScript!');

ブラウザーでページを開き、開発者ツールの「Console」に「こんにちは、JavaScript!」と表示されたら成功です。多くのブラウザーでは、ページ上で右クリックして「検証」を選ぶか、F12キーで開発者ツールを開けます。

deferの役割 defer を付けると、HTMLの解析を妨げずにJavaScriptを読み込み、HTMLの解析が終わってから実行します。後で扱うDOM要素を、読み込み前に探してしまう失敗を避けやすくなります。
エラーも確認する 何も起きないときは、最初にConsoleを確認しましょう。ファイル名やパスの間違い、全角記号の混入、括弧の閉じ忘れなどが表示されます。
03

基本の書き方

文と大文字・小文字

JavaScriptは大文字と小文字を区別します。userNameusername は別の名前です。文末のセミコロンは省略できる場合もありますが、この講座では区切りを分かりやすくするために付けます。

基本構文JAVASCRIPT
console.log('1行目');
console.log('2行目');

コメント

コメントは実行されないメモです。コードの内容をそのまま書き直すのではなく、処理の目的や、その書き方を選んだ理由を残すと役立ちます。

コメントJAVASCRIPT
// 1行のコメント

/*
  複数行のコメント
*/

文字列

文字列はシングルクォート、ダブルクォート、バッククォートで囲めます。バッククォートを使うテンプレートリテラルでは、${} の中へ値を埋め込めます。

テンプレートリテラルJAVASCRIPT
const name = 'Mity';
const message = `こんにちは、${name}さん!`;

console.log(message); // こんにちは、Mityさん!
04

変数とデータ型

変数は値に名前を付けて保存する仕組みです。再代入しない値は const、後から別の値を代入する必要がある場合だけ let を使います。

constとletJAVASCRIPT
const userName = 'Mity'; // 再代入しない
let score = 70;          // 後で変更する

score = 85;

console.log(`${userName}さんの点数は${score}点です`);
varについて 古いコードでは var も見かけますが、スコープなどの挙動が let と異なります。新しく書くコードでは、まず constlet を使い分けましょう。

基本的なデータ型

用途
string'こんにちは'文字列
number203.14数値
booleantruefalse真偽
undefinedlet value;値がまだ代入されていない
nullconst result = null;値がないことを意図的に表す
bigint123n非常に大きな整数

typeof 演算子を使うと、値の型を文字列で確認できます。

型を確認するJAVASCRIPT
const price = 500;
const label = '価格';

console.log(typeof price); // number
console.log(typeof label); // string
constでも中身は変更できる const は変数への再代入を禁止します。配列やオブジェクト自体の中身まで変更できなくなるわけではありません。この違いは配列の章で確認します。
05

演算子と型変換

演算子を使うと計算、比較、条件の組み合わせができます。

種類演算子
算術+ - * / % **price * count
比較=== !== > < >= <=age >= 18
論理&& || !isMember && hasTicket
代入= += -= *= /=total += 100
値がない場合??name ?? 'ゲスト'
料金を計算するJAVASCRIPT
const price = 500;
const count = 3;
const total = price * count;

console.log(`合計は${total}円です`); // 合計は1500円です

===で比較する

=== は値と型の両方を比較します。== は比較前に型を暗黙変換するため、予想しにくい結果になることがあります。

比較の違いJAVASCRIPT
console.log(5 === '5'); // false(数値と文字列)
console.log(5 == '5');  // true(比較前に型変換される)

入力値を数値へ変換する

フォームの value は、数字を入力しても文字列です。計算前に Number() で変換し、Number.isNaN() で変換できたか確認します。

文字列から数値へJAVASCRIPT
const inputValue = '120'; // 実際にはフォームなどから受け取る
const price = Number(inputValue);

if (Number.isNaN(price)) {
    console.log('数値を入力してください');
} else {
    console.log(price * 2); // 240
}
+演算子に注意 '10' + 5 の結果は数値の15ではなく文字列の'105'です。入力値を計算するときは型を確認しましょう。
06

条件分岐

if を使うと、条件に応じて処理を切り替えられます。条件は上から順番に判定され、最初に一致した処理だけが実行されます。

if / else if / elseJAVASCRIPT
const score = 82;

if (score >= 80) {
    console.log('合格です。よくできました!');
} else if (score >= 60) {
    console.log('合格です');
} else {
    console.log('もう一度挑戦しましょう');
}

ひとつの値を複数の候補と比較する場合は switch も使えます。

switchJAVASCRIPT
const day = 1;

switch (day) {
    case 1:
        console.log('月曜日');
        break;
    case 2:
        console.log('火曜日');
        break;
    default:
        console.log('その他');
}
breakを忘れない switchbreak を省くと、次の case の処理も続けて実行されます。意図的な場合を除き、各処理の最後に書きます。
07

繰り返し

回数が分かっている処理には for、条件を満たす間繰り返す処理には while、配列の各要素には for...of が使えます。

forJAVASCRIPT
for (let i = 1; i <= 5; i += 1) {
    console.log(`${i}回目`);
}
whileJAVASCRIPT
let count = 3;

while (count > 0) {
    console.log(count);
    count -= 1;
}

console.log('スタート!');
for...ofJAVASCRIPT
const fruits = ['りんご', 'みかん', 'ぶどう'];

for (const fruit of fruits) {
    console.log(fruit);
}
無限ループに注意 while の条件が永遠に true のままだと処理が終わりません。条件に使う値がループ内で変化することを確認してください。
08

配列

配列には複数の値を順番に保存できます。最初の要素の番号は0です。

配列の基本JAVASCRIPT
const fruits = ['りんご', 'みかん', 'ぶどう'];

console.log(fruits[0]);     // りんご
console.log(fruits.length); // 3

fruits.push('もも');
console.log(fruits);

const で宣言した配列でも push() で要素を追加できます。ただし、fruits = [] のように別の配列を再代入することはできません。

配列を変換・抽出する

map() は各要素を変換した新しい配列、filter() は条件に一致した要素だけの新しい配列を返します。元の配列は変更されません。

mapとfilterJAVASCRIPT
const scores = [72, 95, 48, 81];

const doubled = scores.map((score) => score * 2);
const passed = scores.filter((score) => score >= 60);

console.log(doubled); // [144, 190, 96, 162]
console.log(passed);  // [72, 95, 81]
console.log(scores);  // [72, 95, 48, 81]
破壊的な操作 push()pop()sort() などは元の配列を変更します。元の順番を残したい場合は、const sorted = [...scores].sort((a, b) => a - b); のようにコピーしてから並べ替えます。
09

オブジェクトとクラス

オブジェクトは、関連する値をプロパティ名と組み合わせて保存します。利用者や商品など、複数の項目を持つデータを表すときに便利です。

オブジェクトの基本JAVASCRIPT
const user = {
    name: 'Mity',
    age: 20,
    address: {
        city: '東京',
    },
};

console.log(user.name);         // Mity
console.log(user['age']);       // 20
console.log(user.address.city); // 東京

分割代入と値がない場合

安全に値を読むJAVASCRIPT
const user = {
    name: 'Mity',
    address: null,
};

const { name } = user;
const city = user.address?.city ?? '未登録';

console.log(name); // Mity
console.log(city); // 未登録

?. は途中の値が null または undefined なら処理を止めて undefined を返します。?? は左側が null または undefined のときだけ右側を使います。

クラスからオブジェクトを作る

同じ構造と処理を持つオブジェクトを複数作る場合は、クラスを設計図として利用できます。constructornew でオブジェクトを作るときに呼ばれ、this は作成されたオブジェクト自身を表します。

クラスJAVASCRIPT
class User {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    introduce() {
        return `${this.name}、${this.age}歳です`;
    }
}

const user = new User('Mity', 20);
console.log(user.introduce()); // Mity、20歳です
10

関数とスコープ

関数は、まとまった処理に名前を付けて再利用する仕組みです。引数で値を受け取り、return で結果を返します。

関数宣言JAVASCRIPT
function calculateTotal(price, count) {
    return price * count;
}

const total = calculateTotal(500, 3);
console.log(`合計は${total}円です`);

短い処理ではアロー関数もよく使われます。引数がひとつなら括弧を省略できますが、書き始めは括弧を付けても問題ありません。

アロー関数JAVASCRIPT
const double = (number) => number * 2;

console.log(double(5)); // 10

ブロックスコープ

constlet で宣言した変数は、宣言した波括弧の外からは利用できません。

スコープJAVASCRIPT
if (true) {
    const message = 'ブロックの中だけで使えます';
    console.log(message);
}

// console.log(message); // ReferenceError
アロー関数のthis アロー関数は通常の関数と this の扱いが異なります。配列の map() などのコールバックには便利ですが、オブジェクトのメソッドで this を使う場合は違いを確認してから選びましょう。
11

HTMLを操作する(DOM)

ブラウザーはHTMLをDOMというオブジェクトの集まりとして扱います。document.querySelector() で要素を探し、プロパティやメソッドを使って内容を変更できます。

index.htmlHTML
<p id="message">変更前の文章</p>
<ul id="fruitList"></ul>
app.jsJAVASCRIPT
const message = document.querySelector('#message');
const fruitList = document.querySelector('#fruitList');

if (message !== null) {
    message.textContent = 'JavaScriptで変更しました';
    message.classList.add('is-updated');
}

const fruits = ['りんご', 'みかん', 'ぶどう'];

if (fruitList !== null) {
    for (const fruit of fruits) {
        const item = document.createElement('li');
        item.textContent = fruit;
        fruitList.append(item);
    }
}

querySelector() は一致する要素がない場合に null を返します。要素が必ず存在すると思い込まず、条件分岐で確認すると「nullのプロパティを読めない」というエラーを防げます。

innerHTMLとXSS ユーザー入力や外部データを innerHTML へ代入すると、悪意のあるHTMLやスクリプトが実行される危険があります。単なる文字として表示する場合は textContent を使いましょう。
12

イベントとフォーム

クリック、入力、送信など、ページ上で起きた出来事をイベントと呼びます。addEventListener() を使って、イベントが起きたときの処理を登録します。

クリックで表示を切り替える

index.htmlHTML
<button id="toggleButton" type="button">表示を切り替える</button>
<p id="detail" hidden>詳しい説明です。</p>
app.jsJAVASCRIPT
const toggleButton = document.querySelector('#toggleButton');
const detail = document.querySelector('#detail');

if (toggleButton !== null && detail !== null) {
    toggleButton.addEventListener('click', () => {
        detail.hidden = !detail.hidden;
    });
}

フォームの入力を確認する

index.htmlHTML
<form id="nameForm">
    <label for="nameInput">お名前</label>
    <input id="nameInput" name="name" type="text" required>
    <button type="submit">送信</button>
</form>
<p id="formMessage" aria-live="polite"></p>
app.jsJAVASCRIPT
const form = document.querySelector('#nameForm');
const nameInput = document.querySelector('#nameInput');
const formMessage = document.querySelector('#formMessage');

if (form !== null && nameInput !== null && formMessage !== null) {
    form.addEventListener('submit', (event) => {
        event.preventDefault();

        const name = nameInput.value.trim();

        if (name === '') {
            formMessage.textContent = '名前を入力してください';
            return;
        }

        formMessage.textContent = `こんにちは、${name}さん!`;
    });
}

event.preventDefault() は、フォーム送信によるページ移動を止めます。この例はブラウザー内で表示を確認する練習用です。実際にサーバーへデータを保存する場合は、送信先でも入力値を必ず検証してください。

ブラウザーの確認だけでは不十分 JavaScriptの検証は利用者が無効化・変更できます。セキュリティやデータの正しさに関わる検証は、PHPなどのサーバー側でも必ず行います。
13

非同期処理とFetch API

通信には時間がかかるため、結果を待つ間もページ全体を止めない非同期処理を使います。async 関数の中では、Promiseの完了を await で待てます。

次の例では、同じサイトに置いたJSONファイルを読み込みます。3つのファイルを同じフォルダー構成で用意してください。

data/users.jsonJSON
[
    { "id": 1, "name": "Mity" },
    { "id": 2, "name": "Sora" }
]
index.htmlHTML
<button id="loadButton" type="button">利用者を読み込む</button>
<p id="loadStatus" aria-live="polite"></p>
<ul id="userList"></ul>
app.jsJAVASCRIPT
const loadButton = document.querySelector('#loadButton');
const loadStatus = document.querySelector('#loadStatus');
const userList = document.querySelector('#userList');

async function loadUsers() {
    if (loadStatus === null || userList === null) {
        return;
    }

    loadStatus.textContent = '読み込み中です...';

    try {
        const response = await fetch('./data/users.json');

        if (!response.ok) {
            throw new Error(`HTTPエラー: ${response.status}`);
        }

        const users = await response.json();
        userList.replaceChildren();

        for (const user of users) {
            const item = document.createElement('li');
            item.textContent = user.name;
            userList.append(item);
        }

        loadStatus.textContent = '読み込みました';
    } catch (error) {
        console.error(error);
        loadStatus.textContent = '読み込みに失敗しました';
    }
}

if (loadButton !== null) {
    loadButton.addEventListener('click', loadUsers);
}

fetch() は、404や500などのHTTPエラーでは自動的に例外を投げません。response.ok を確認し、失敗なら自分でエラーを投げます。ネットワーク障害やJSONの解析失敗も起こり得るため、try...catch で利用者向けの表示を用意します。

Promiseとthen・catch

async 関数はPromiseを返し、await はその完了を待つ書き方です。同じPromiseは then() で成功後の処理、catch() で失敗時の処理をつなげることもできます。既存のコードやドキュメントでは、次の形式もよく見かけます。

thenとcatchで書くJAVASCRIPT
fetch('./data/users.json')
    .then((response) => {
        if (!response.ok) {
            throw new Error(`HTTPエラー: ${response.status}`);
        }

        return response.json();
    })
    .then((users) => {
        console.log(users);
    })
    .catch((error) => {
        console.error('読み込みに失敗しました', error);
    });
どちらを使うか asyncawaitthen()catch() は、どちらもPromiseを扱います。プロジェクトの書き方に合わせ、ひとつの処理の中では読みやすい形式に揃えましょう。
ファイルを直接開かない Fetchや後述のモジュールは、file:// でHTMLを直接開くとブラウザーのセキュリティ制限で失敗することがあります。ローカル開発サーバーを使い、http://localhost から確認してください。
14

ブラウザーへデータを保存する

localStorage を使うと、同じオリジンのブラウザーへ文字列を保存できます。ページを閉じても残るため、テーマ設定や入力途中の下書きなどに利用できます。

文字列を保存するJAVASCRIPT
localStorage.setItem('theme', 'dark');

const theme = localStorage.getItem('theme') ?? 'light';
console.log(theme); // dark

localStorage.removeItem('theme');

localStorageが保存できるのは文字列だけです。配列やオブジェクトは JSON.stringify() で文字列へ変換し、読み込むときに JSON.parse() で元へ戻します。

オブジェクトを保存するJAVASCRIPT
let savedSettings = null;

try {
    const settings = {
        theme: 'dark',
        fontSize: 16,
    };

    localStorage.setItem('settings', JSON.stringify(settings));

    const savedText = localStorage.getItem('settings');

    if (savedText !== null) {
        savedSettings = JSON.parse(savedText);
    }
} catch (error) {
    console.error('設定を保存または読み込みできませんでした', error);
}

console.log(savedSettings);

タブを閉じるまで保存する

sessionStoragelocalStorage と同じく文字列を保存しますが、データはブラウザーのタブごとに分かれ、そのタブを閉じると削除されます。同じタブでの再読み込みでは残るため、ページを開いている間だけ保持したい入力内容などに使えます。

sessionStorageJAVASCRIPT
sessionStorage.setItem('draft', '入力途中の文章');

const draft = sessionStorage.getItem('draft') ?? '';
console.log(draft); // 入力途中の文章

sessionStorage.removeItem('draft');
秘密情報を保存しない localStorageとsessionStorageの内容はJavaScriptから読み取れます。パスワード、認証トークン、カード番号などの秘密情報は保存しないでください。容量には上限があり、プライベートブラウズや利用者の設定によって保存に失敗する場合もあります。
保存場所はURLごとに分かれる HTTPとHTTPS、ドメイン、ポートが違えば別の保存領域です。file:// で直接開いたページの挙動はブラウザーによって異なるため、ここでもローカル開発サーバーを使いましょう。
15

モジュールとエラーの調べ方

ファイルを役割ごとに分ける

コードが増えたら、関数や値を別ファイルへ分けます。公開する側で export、利用する側で import を使い、HTMLでは type="module" を指定します。

math.jsJAVASCRIPT
export function add(a, b) {
    return a + b;
}
main.jsJAVASCRIPT
import { add } from './math.js';

console.log(add(2, 3)); // 5
index.htmlHTML
<script type="module" src="main.js"></script>

モジュールの相対パスには ./ と拡張子を含めます。ブラウザーではWebサーバーから正しいJavaScriptのContent-Typeで配信する必要があるため、HTMLを直接開かずローカル開発サーバーを使います。

エラーを段階的に調べる

確認する順番
  1. Consoleの最初のエラーメッセージと行番号を読む
  2. 変数が定義され、想定した型と値になっているか確認する
  3. DOM要素が null になっていないか確認する
  4. NetworkパネルでJSやJSONのURLとHTTPステータスを見る
  5. console.log() やブレークポイントで処理の順番を追う
例外を処理するJAVASCRIPT
function calculateAverage(scores) {
    if (scores.length === 0) {
        throw new Error('点数がありません');
    }

    const total = scores.reduce((sum, score) => sum + score, 0);
    return total / scores.length;
}

try {
    console.log(calculateAverage([]));
} catch (error) {
    console.error(error.message); // 点数がありません
}

この例では空配列を意図的に渡し、エラー処理の動作を確認しています。エラーを無視して処理を続けるのではなく、利用者向けの表示と開発者向けの記録を分けて考えましょう。

16

練習問題

問題 11から100までの合計を求めよう

for を使って1から100までの数を total へ足し、Consoleへ表示してください。

解答例JAVASCRIPT
let total = 0;

for (let i = 1; i <= 100; i += 1) {
    total += i;
}

console.log(total); // 5050
問題 2合格者の名前を取り出そう

利用者の配列から60点以上の人を選び、名前だけの新しい配列を作ってください。

解答例JAVASCRIPT
const users = [
    { name: 'Mity', score: 82 },
    { name: 'Sora', score: 55 },
    { name: 'Haru', score: 91 },
];

const passedNames = users
    .filter((user) => user.score >= 60)
    .map((user) => user.name);

console.log(passedNames); // ['Mity', 'Haru']
問題 3カウンターを作ろう

ボタンを押すたびに数字が1増えるページを作ってください。

HTMLHTML
<button id="countButton" type="button">1増やす</button>
<p>回数: <span id="countValue">0</span></p>
JavaScriptJAVASCRIPT
const countButton = document.querySelector('#countButton');
const countValue = document.querySelector('#countValue');
let count = 0;

if (countButton !== null && countValue !== null) {
    countButton.addEventListener('click', () => {
        count += 1;
        countValue.textContent = String(count);
    });
}
NEXT

次に学ぶこと

ここまで理解できたら、短い機能を組み合わせて自分のWebページを作ってみましょう。最初から大きなアプリを目指さず、入力、表示、保存、読み込みを一つずつ追加するのがおすすめです。

作ってみたい題材 ToDoリスト、画像ギャラリー、クイズ、テーマ切り替え、APIから天気を読むページなどは、基礎を組み合わせる練習に向いています。公開APIを使う場合は利用規約、認証情報の扱い、アクセス回数の制限も確認してください。
← 学習一覧へ戻る