実践JavaScriptの導入スライド

36 件(作成済み 26・導入不要 0・未作成 10・合計 104枚 / 26本)

レッスンの導入の索引へ戻る

実践JavaScriptのコースサムネイル
実践JavaScript1レッスン

このコースで育てるもの

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript2レッスン

strict mode で書き間違いを表に出す

導入スライド 4

実践JavaScript - strict mode で書き間違いを表に出す

ファイルの先頭に 1 行足す

JavaScript には、判定をゆるくしたまま動く既定のモードと、厳しく判定する strict mode の 2 つがあります。ファイルの先頭に 1 行書くだけで、そのファイル全体が厳しいほうに切り替わります。

正しく書けているコードの動きは何も変わりません。変わるのは、書き間違えたときの扱いです。

先頭に置いたこの 1 行が、そのファイル全体の判定を厳しくします。

"use strict"; let viewCount = 0; viewCount = 12; console.log(viewCount); // 12

1 / 4

宣言し忘れた変数に代入してみる

作品の閲覧数を数える変数を用意したつもりで、代入する側の名前を 1 文字打ち間違えた場面です。同じコードを 2 つのモードで動かすと、返ってくるものが変わります。

"use strict";
"use strict"ここで切り替える
let viewCount = 0;
viewCont = 12;
viewCont =打ち間違えた名前
console.log(viewCount);

モードごとの結果

書いた行strict mode なしstrict mode あり
viewCont = 12;viewCont という別の変数ができるReferenceError で止まる
console.log(viewCount);0 が出るここまで届かない
NaN = 0;黙って無視されるTypeError で止まる
function f(a, a) {}後ろの a が使われるSyntaxError で読み込めない

左の列では、打ち間違えたほうが正しい書き方として通ってしまいます。

strict mode なしだと、閲覧数が 0 のままの原因を最後まで自分で探すことになります。

2 / 4

考えてみよう外しても進めます

strict mode にしていないファイルで、宣言していない名前にいきなり代入するとどうなるでしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

strict mode が先に止めてくれるもの

止まる書き方は決まっています。どれも、動かしたあとで原因を探すと時間がかかる種類のものです。

strict mode で止まる書き方止めなかった場合に起きること

宣言していない変数への代入

打ち間違えた名前のグローバル変数が増える

NaN や undefined への代入

代入したつもりの値が消える

同じ名前の引数を 2 つ書く

後ろの引数だけが使われる

読み取り専用のプロパティへの代入

書けていないのに次の行へ進む

この章で書くコードは、すべて先頭に use strict を置いた状態で進めます。

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript3レッスン

作品データと表示を分けて持つ

導入スライド 4

実践JavaScript - 作品データと表示を分けて持つ

作品データを 1 か所に集める

ポートフォリオに並べる作品を、HTML に直接書かずに配列として持ちます。1 件ぶんの項目をそろえておくと、あとから件数が増えても同じ扱いのまま足せます。

この配列が、この先ずっと画面のもとになります。あとで中身を API から取ってくる形に差し替えます。

作品 1 件を 1 つのオブジェクトにして、それを配列に並べます。

const works = [ { title: "レシピ検索サイト", year: 2024, tags: ["HTML", "CSS"], views: 1200 }, { title: "家計簿アプリ", year: 2025, tags: ["JavaScript"], views: 860 }, ]; console.log(works.length); // 2 console.log(works[0].title); // "レシピ検索サイト"

1 / 4

表示用の文字列を作る関数を切り出す

画面に出す文字列を組み立てる仕事を、データとは別の関数に分けます。1 件を受け取って 1 本の文字列を返すだけの関数にしておくと、呼ぶ側は中身の作り方を知らずに済みます。

function formatWork(work) {
work作品 1 件を受け取る
return work.title + " (" + work.year + ") " + work.views + " view";
work.title + " ("表示の形はここだけで決める
}
for (const work of works) {
for (const work of works)配列を回すのは呼ぶ側
console.log(formatWork(work));
}

出力

呼び出し返る文字列
formatWork(works[0])レシピ検索サイト (2024) 1200 view
formatWork(works[1])家計簿アプリ (2025) 860 view

表示の形を変えたくなったら、直すのは formatWork の中だけです。

データを持つ場所と、見せ方を決める場所が別々になりました。

2 / 4

考えてみよう外しても進めます

works の中身を、同じ項目名 (title, year, views) のまま API から取ってきた配列に差し替えました。書き直しが必要になるのはどこでしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

3 つの役割に分けて考える

ここで作った形は、この先どのレッスンでも同じです。役割ごとに置き場所を分けておくと、変更したい所だけを開けば済みます。

データを持つ

works の配列。項目名と件数だけを決める

表示の形を決める

formatWork。1 件を受け取って文字列を返す

画面に置く

配列を回して、返ってきた文字列を並べる

次の章では、真ん中の formatWork をそのままにしたまま、一番上の works の作り方だけを取り替えていきます。

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript4レッスン

第1章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript5レッスン

map で形を変える

導入スライド 4

実践JavaScript - map で形を変える

1件ずつ別の形に置き換える

ポートフォリオの作品配列から、画面に出したいのは題名だけ、ということがあります。map は元の配列を 1 件ずつ見て、返した値を並べた新しい配列を作ります。元の配列はそのまま残ります。

4 件を渡したら 4 件が返ります。map は件数を変えません。変わるのは 1 件ずつの形だけです。

この works をこの章の最後まで使い回します。中身を覚えておいてください。

const works = [ { title: "旅の記録サイト", year: 2023, views: 320, published: true }, { title: "家計簿アプリ", year: 2024, views: 1250, published: true }, { title: "写真ギャラリー", year: 2024, views: 860, published: false }, { title: "天気ボット", year: 2025, views: 540, published: true }, ]; const titles = works.map((w) => w.title); console.log(titles.length); // 4 console.log(titles[1]); // "家計簿アプリ"

1 / 4

forEach と map は戻り値で見分ける

どちらも 1 件ずつ関数を呼びます。違うのは、関数が返した値を集めるかどうかです。forEach は集めないので、戻り値は undefined になります。

const a = works.forEach((w) => w.title);
forEach返した値を捨てる
const b = works.map((w) => w.title);
map返した値を集める

受け取った値

変数中身件数
aundefined
b["旅の記録サイト", …]4

a は undefined なので、このあと a.length と書いた時点で落ちます。

戻り値を使いたいなら map、ただ 1 件ずつ何かしたいだけなら forEach という分かれ方です。

2 / 4

考えてみよう外しても進めます

works.map((w) => { w.title; }) と、波かっこで囲んで書いた場合、返ってくる配列の中身はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - map で形を変える

map でよく作る形

返す値は文字列に限りません。オブジェクトを返せば、画面が欲しい形の配列をそのまま組み立てられます。

オブジェクトを返すときは丸かっこで囲みます。囲まないと波かっこが関数の本体だと読まれてしまいます。

やりたいこと書き方
1 つの項目だけ抜くworks.map((w) => w.title)
文字列に整えるworks.map((w) => w.title + " / " + w.year)
別のオブジェクトにするworks.map((w) => ({ label: w.title, hot: w.views > 800 }))
番号を振るworks.map((w, i) => i + 1 + w.title)
1 件ずつ表示するだけworks.forEach((w) => console.log(w.title))

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript6レッスン

filter と find で絞り込む

導入スライド 4

実践JavaScript - filter と find で絞り込む

条件に合うものを取り出す 2 つの道具

map が形を変える道具だとすると、filter と find は数を減らす道具です。filter は条件に合ったものを全部、find は最初に見つかった 1 件だけを返します。

写真ギャラリーは views が 860 で条件に合いますが、家計簿アプリのほうが前にあるので find はそこで止まります。

filter が返すのは配列、find が返すのは要素そのものです。ここが最初の分かれ目です。

const published = works.filter((w) => w.published); console.log(published.length); // 3 const first = works.find((w) => w.views > 800); console.log(first.title); // "家計簿アプリ"

1 / 4

filter は真になった行だけを残す

渡した関数が true を返した要素だけが新しい配列に入ります。false だった要素は捨てられ、元の配列には手が付きません。

const hits = works.filter((w) => w.views >= 500);
filter残すか捨てるかを決める
w.views >= 500真なら残る

hits

titleviews判定
旅の記録サイト320false
家計簿アプリ1250true
写真ギャラリー860true
天気ボット540true

取り消し線の 1 行は false なので hits に入りません。4 件が 3 件になります。

条件を厳しくするほど残る件数は減ります。0 件になっても空の配列が返るだけで、エラーにはなりません。

2 / 4

考えてみよう外しても進めます

works.find((w) => w.year === 2030) のように、どれも当てはまらない条件を書いたとき、返ってくるのは何ですか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - filter と find で絞り込む

見つからなかったときの戻り値

絞り込みの関数は、空振りしたときに何を返すかがそれぞれ違います。ここを取り違えると、条件に合う作品が無い日だけ画面が落ちます。

find の結果をそのまま使う前に、if (first) で受け止めるか、?. をはさんでおくと安全です。

書き方1 件も当てはまらないとき
filter空の配列 []
findundefined
findIndex-1
somefalse
everytrue (空配列は常に true)

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript7レッスン

reduce でひとつにまとめる

導入スライド 4

実践JavaScript - reduce でひとつにまとめる

配列を 1 つの値にたたみ込む

map も filter も、返ってくるのは配列でした。reduce は配列を受け取って、最後に値を 1 つだけ返します。合計や最大値のように、全体を見ないと決まらないものを作るときに使います。

いちばん後ろの 0 が初期値です。sum の 1 回目の値がここから始まります。

sum は前回の結果、w は今見ている 1 件です。最後の sum がそのまま total になります。

const total = works.reduce((sum, w) => sum + w.views, 0); console.log(total); // 2970

1 / 4

sum がどう育つかを追う

reduce は 1 件ずつ関数を呼び、返した値を次の回の sum として渡します。途中の値はどこにも残らず、最後に返ったものだけが手に入ります。

const total = works.reduce((sum, w) => sum + w.views, 0);
sum前回の結果
w.views今の 1 件
, 0)初期値

途中経過

sum (入るとき)w.views返す値
10320320
232012501570
315708602430
424305402970

囲った 4 回目の返り値が、そのまま total になります。

1 回目の sum が 0 なのは、初期値に 0 と書いたからです。ここを 1000 にすれば結果は 3970 になります。

2 / 4

考えてみよう外しても進めます

初期値を省いて works.reduce((sum, w) => sum + w.views) と書き、works が空配列だったらどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - reduce でひとつにまとめる

初期値をオブジェクトにする

初期値は数値でなくてもかまいません。空のオブジェクトから始めれば、集計結果を項目ごとに持った 1 つのオブジェクトを組み立てられます。

初期値が返り値の形を決めます。数値から始めれば数値、オブジェクトから始めればオブジェクトが返ります。

波かっこで書いた本体では return を忘れないでください。返し忘れると次の acc が undefined になります。

const stat = works.reduce( (acc, w) => { acc.count += 1; acc.views += w.views; return acc; }, { count: 0, views: 0 }, ); console.log(stat); // { count: 4, views: 2970 }

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript8レッスン

sort と比較関数

導入スライド 4

実践JavaScript - sort と比較関数

sort は元の配列を並べ替える

map や filter は新しい配列を作りますが、sort は違います。呼んだ配列そのものを並べ替えてしまい、しかも比較関数を省くと値を文字列として比べます。

nums のほうも並びが変わっています。返ってきた配列は、元の配列と同じものです。

9 が最後に来ています。数値ではなく文字として比べた結果です。

const nums = [10, 9, 100, 1]; const sorted = nums.sort(); console.log(sorted); // [1, 10, 100, 9] console.log(nums); // [1, 10, 100, 9]

1 / 4

比較関数を渡し、複製してから並べ替える

比較関数は 2 件を受け取り、負の数を返せば a が前、正の数を返せば b が前になります。並べ替える前に配列を複製しておけば、元の並びも残せます。

const byViews = [...works]
[...works]先に複製する
.sort((a, b) => b.views - a.views);
b.views - a.views大きいほうが前

byViews

titleviews
1家計簿アプリ1250
2写真ギャラリー860
3天気ボット540
4旅の記録サイト320

works のほうは元の並びのままです。並べ替わったのは複製した配列だけです。

a.views - b.views に書き換えれば昇順になります。引き算の向きが並び順の向きです。

2 / 4

考えてみよう外しても進めます

画面の並べ替えボタンで works.sort((a, b) => a.year - b.year) を直接呼び、そのあと元の順で一覧を出そうとするとどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - sort と比較関数

並べ替えの書き方

比較関数の中身と、元の配列を壊さない書き方を並べて覚えておくと、並べ替えで迷う場面はほとんど無くなります。

文字列は引き算ができないので localeCompare を使います。日本語の並びもこれで決まります。

やりたいこと書き方
数値の昇順arr.sort((a, b) => a - b)
数値の降順arr.sort((a, b) => b - a)
項目で昇順arr.sort((a, b) => a.views - b.views)
文字列の順arr.sort((a, b) => a.title.localeCompare(b.title))
元を壊さない[...arr].sort(...) または arr.toSorted(...)

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript9レッスン

分類してまとめる groupBy

導入スライド 4

実践JavaScript - 分類してまとめる groupBy

年ごとに作品を束ねる

一覧を年で見出し分けしたいとき、欲しいのは年をキーにしたオブジェクトです。reduce の初期値を空のオブジェクトにすると、この形をそのまま組み立てられます。

キーは文字列になります。数値の 2024 で書いても、取り出すときの鍵は "2024" です。

acc は育っていく 1 つのオブジェクトです。毎回同じものを返しているだけです。

const byYear = works.reduce((acc, w) => { if (!acc[w.year]) acc[w.year] = []; acc[w.year].push(w.title); return acc; }, {}); console.log(byYear[2024].length); // 2 console.log(Object.keys(byYear)); // ["2023", "2024", "2025"]

1 / 4

束ねたあとの形を見る

4 件の配列が、3 つの鍵を持つオブジェクトになります。件数が減ったのではなく、同じ年のものが同じ配列に入っただけです。

if (!acc[w.year]) acc[w.year] = [];
if (!acc[w.year]) acc[w.year] = []無ければ入れ物を作る
acc[w.year].push(w.title);
push(w.title)その入れ物に足す
return acc;

byYear

束ねた作品件数
2023旅の記録サイト1
2024家計簿アプリ, 写真ギャラリー2
2025天気ボット1

囲った 2024 だけが 2 件です。同じ年の 2 件が 1 つの配列に入っています。

足し合わせると 4 件に戻ります。捨てた要素は 1 件もありません。

2 / 4

考えてみよう外しても進めます

入れ物を作る 1 行を消して、いきなり acc[w.year].push(w.title) と書いたらどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 分類してまとめる groupBy

束ねかたの選びかた

鍵の作りかたを変えれば、年以外でも同じ形で束ねられます。値のほうも、配列にするか数だけ数えるかを選べます。

Object.groupBy という新しい書き方もありますが、動く場所がまだ限られます。reduce で書ければどこでも通ります。

やりたいこと鍵と値の作りかた
年ごとに作品を並べる鍵は w.year、値は配列に push
年ごとの件数だけ欲しいacc[w.year] = (acc[w.year] || 0) + 1
公開と非公開で分ける鍵は w.published ? "公開" : "下書き"
年と月で分ける鍵は w.year + "-" + w.month
取り出すときの鍵常に文字列。Object.keys で一覧できる

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript10レッスン

つなげて組み立てる

導入スライド 4

実践JavaScript - つなげて組み立てる

3 つの道具を 1 本につなぐ

filter も sort も map も、返ってくるのは配列です。だから続けて呼べます。公開中のものだけを閲覧数の多い順に並べて題名にする、という処理が 3 行で書けます。

先頭で複製しているのは sort のためです。filter が新しい配列を返すので実は要りませんが、先頭に置く癖にしておくと事故りません。

点が縦に並ぶ書き方です。上から順に、左の結果が次の入力になります。

const list = [...works] .filter((w) => w.published) .sort((a, b) => b.views - a.views) .map((w) => w.title); console.log(list); // ["家計簿アプリ", "天気ボット", "旅の記録サイト"]

1 / 4

つなぐ順番で仕事の量が変わる

filter を先に置けば、そのあとの sort と map は残った 3 件だけを相手にします。sort を先に置くと、あとで捨てる 1 件まで並べ替えることになります。

[...works]
.filter((w) => w.published)
.filter((w) => w.published)ここで 4 件が 3 件になる
.sort((a, b) => b.views - a.views)
.sort((a, b) => b.views - a.views)並べ替えるのは 3 件だけ
.map((w) => w.title);

filter で減らして sort で並べたあと

titlepublishedviews
家計簿アプリtrue1250
天気ボットtrue540
旅の記録サイトtrue320
写真ギャラリーfalse860

取り消し線の 1 件は sort にも map にも渡りません。囲った行が先頭に来ます。

件数の多い一覧ほど差が出ます。減らす処理を前に、並べ替えを後ろに置くのが基本の並びです。

2 / 4

考えてみよう外しても進めます

map を先頭に置いて .map((w) => w.title).sort((a, b) => b.views - a.views) と書くとどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

つなぐ順番の目安

どの順でも書けてしまうぶん、置き場所は自分で決めることになります。迷ったらこの並びに寄せておけば、結果も速さも素直になります。

いちばん前

複製の [...arr]。sort で元を壊さないため

前のほう

filter。相手にする件数をここで減らす

真ん中

sort。減らしたあとの件数だけを並べ替える

いちばん後ろ

map。表示に必要な形へ最後に変える

reduce だけはこの並びに入りません。1 つの値にたたむので、つなげずにそこで終わります。map を前に置くと、後ろで使いたかった項目が消えます。形を変えるのは、絞り込みと並べ替えが終わってからです。

4 / 4

実践JavaScriptのコースサムネイル導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript12レッスン

第2章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript13レッスン

クロージャで状態を閉じ込める

導入スライド 4

実践JavaScript - クロージャで状態を閉じ込める

前回の値を覚える置き場所がいる

作品カードが開かれた回数を数えたいとき、数を入れておく変数が必要になります。グローバルに置くと誰からでも書き換えられるので、関数の中に閉じ込めたまま増やせる形にします。

中で作った変数が外から見えない、という前提があって初めてこの閉じ込めが成り立ちます。次の図解でその壁を見ます。

createCounter が返した関数は、外に持ち出されたあとも中の count を覚えたままです。

function createCounter() { let count = 0; return function () { count += 1; return count; }; } const countView = createCounter(); console.log(countView()); // 1 console.log(countView()); // 2

1 / 4

実践JavaScript - クロージャで状態を閉じ込める

内と外のどちらから見えるか

変数を置く場所と参照する場所を切り替えて、見える組み合わせを探してください。

  • 「そと」に置いて「うち」で参照すると値が出る。関数の中から外の変数は見える
  • 「うち」に置いて「そと」で参照したときだけ枠が曇り、名前が見つからないエラーになる
  • 4 通りのうち塞がるのはこの 1 通りだけ。この壁が count を守っている
スコープの内と外

2 / 4

考えてみよう外しても進めます

countView を 2 回呼んだあと、createCounter の中の count を関数の外から直接読もうとするとどうなるでしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

作るたびに別の状態を持つ

createCounter を呼ぶたびに、新しい count が 1 つずつ作られます。返ってきた関数はそれぞれ自分の count だけを見るので、数え方が混ざりません。

const countA = createCounter();
const countA1 つめの count を持つ
const countB = createCounter();
const countB別の count を持つ
countA();
countA();
countB();

戻り値

呼び出し戻り値
countA()1
countA()2
countB()1

囲った行は 3 回目の呼び出しですが 1 に戻っています。countB は自分の count しか見ていないからです。

グローバル変数を 1 つも増やさずに、数えたい数だけカウンタを用意できます。

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript14レッスン

設定を覚えた関数をつくる

導入スライド 4

実践JavaScript - 設定を覚えた関数をつくる

しきい値を先に受け取っておく

作品を閲覧数で絞りたいとき、しきい値を関数の中に直接書くと 1 つの値でしか使えません。しきい値を先に受け取り、それを覚えた判定関数を返す形にします。

この判定関数は引数を 1 つしか取りません。だから filter にそのまま渡せます。

minViews が返すのは判定の結果ではなく、しきい値を覚えた判定関数そのものです。

function minViews(threshold) { return function (work) { return work.views >= threshold; }; } const isPopular = minViews(800); console.log(isPopular({ title: "家計簿アプリ", views: 340 })); // false

1 / 4

作った判定関数をそのまま filter に渡す

filter は「1 件を受け取って真偽を返す関数」を求めます。設定を先に渡して作った関数はちょうどその形なので、間に無名関数を挟まずに渡せます。

const isPopular = minViews(800);
minViews(800)設定を渡すのはここだけ
const popular = works.filter(isPopular);
works.filter(isPopular)作った関数をそのまま渡す

popular

titleviews
料理レシピ検索1200
家計簿アプリ340
天気ダッシュボード890
ポートフォリオサイト520
タスク管理ツール2100

取り消し線の 2 件は 800 未満なので残りません。しきい値を変えたいときは minViews(500) と作り直します。

しきい値ごとに別の関数を作れるので、同じ配列に対して何通りもの絞り込みを並べられます。

2 / 4

考えてみよう外しても進めます

minViews(800) を実行したとき、変数に入るのは何でしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 設定を覚えた関数をつくる

設定を先に渡す形の作り分け

同じ書き方で、絞り込みも変換も作れます。設定を受け取る外側と、1 件を受け取る内側の 2 段に分けるのが共通の形です。

設定を渡すのは作るときの 1 回だけです。使うときの呼び出しは引数 1 つのままなので、filter にも map にも同じ形で渡せます。

やりたいこと作り方
閲覧数が指定以上の作品だけ残すminViews(800)
指定した年以降の作品だけ残すsinceYear(2024)
指定したタグを含む作品だけ残すhasTag("React")
数値に単位を付けて表示するwithUnit("回")
作った関数を使うworks.filter(minViews(800))

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript15レッスン

関数を返す関数

導入スライド 4

実践JavaScript - 関数を返す関数

変換を並べて 1 本にまとめる

前後の空白を落として、長さを切り詰めて、と変換が続くと呼び出しが入れ子になって読めなくなります。処理の順番を配列で受け取り、順に通す関数を組み立てて返します。

return が組み立てた関数を外へ出す唯一の出口です。この出口が塞がると何が返るのかを次の図解で見ます。

pipe が返すのは変換の結果ではなく、2 つの変換を順に通す 1 本の関数です。

function pipe(steps) { return function (value) { return steps.reduce((current, step) => step(current), value); }; } const trim = (s) => s.trim(); const short = (s) => s.slice(0, 8); const toLabel = pipe([trim, short]); console.log(toLabel(" 料理レシピ検索アプリ ")); // "料理レシピ検索ア"

1 / 4

実践JavaScript - 関数を返す関数

出口を塞ぐと何が返るか

スライダーを動かしたあと、return を書かないトグルを入れてください。

  • スライダーを動かすと、右の玉の値が渡した数の 2 倍に変わる
  • トグルを入れると出口の矢印が点線になり、途中にバツ印が出て塞がれる
  • そのとき右の玉から値が消える。中では計算しているのに外へ出ていない
関数の引数と戻り値

2 / 4

考えてみよう外しても進めます

pipe の中で、組み立てた関数を return し忘れたまま toLabel を呼ぶとどうなるでしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

組み立てた関数を map に渡す

1 本にまとめてしまえば、あとは map に渡すだけです。作品ごとに同じ順番の変換が通るので、途中の入れ子を書かずに済みます。

const toLabel = pipe([trim, short]);
pipe([trim, short])順番を配列で渡す
const labels = works.map((work) => toLabel(work.title));
works.map各作品に同じ関数を通す

labels

元の titlemap の結果
料理レシピ検索アプリ 料理レシピ検索ア
家計簿アプリ家計簿アプリ
天気ダッシュボード天気ダッシュボー
タスク管理ツールタスク管理ツール

囲った行は空白が落ちてから 8 文字で切られています。8 文字以下の作品名はそのまま残ります。

変換の順番を変えたいときは、pipe に渡す配列の並びを差し替えるだけで済みます。

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript16レッスン

副作用のない関数

導入スライド 4

実践JavaScript - 副作用のない関数

渡した配列が書き換わってしまう

関数に配列を渡すと、中身のオブジェクトは呼んだ側と同じものです。関数の中でその場で書き換えると、戻り値を受け取ったつもりが元の変数まで変わります。

コピーしたつもりで同じものを指している、というのがこの事故の中身です。次の図解で箱と矢印の数を数えます。

result を見ているつもりが、元の works の中身まで 440 になっています。

const works = [{ title: "家計簿アプリ", views: 340 }]; function boost(list) { list[0].views += 100; return list; } const result = boost(works); console.log(works[0].views); // 440

1 / 4

実践JavaScript - 副作用のない関数

箱はいくつ作られているか

コピーのトグルを切り替えて、箱がいくつ作られるか見比べてください。

  • トグルが OFF のとき箱は 1 つだけ。2 本の矢印が同じ箱に集まっている
  • その箱に 9 を足すと、片方しか触っていないのに両方の中身が変わる
  • トグルを入れると箱が 2 つに分かれ、もう一方は元の [1, 2, 3] のまま残る
参照とコピー

2 / 4

考えてみよう外しても進めます

元の works を書き換えずに、閲覧数を 100 増やした配列を作りたいときはどれでしょうか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

元を残して新しい配列を返す

受け取った値には触れず、新しいオブジェクトを組み立てて返します。同じ引数なら何度呼んでも同じ結果になり、呼んだ側の変数も無事です。

const boosted = works.map((work) => ({
...work,
...work元の値を写す
views: work.views + 100,
views: work.views + 100この列だけ差し替える
}));

呼び出したあと

titleworks の viewsboosted の views
料理レシピ検索12001300
家計簿アプリ340440
天気ダッシュボード890990

囲った行を見ると、真ん中の列は 340 のままです。元の配列はどこも変わっていません。

同じ引数なら同じ戻り値を返し、外の値に触れない関数を純粋な関数と呼びます。テストが書きやすいのも、結果が呼ぶ順番に左右されないからです。

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript17レッスン

第3章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript18レッスン

分割代入で必要な値だけ取り出す

導入スライド 4

実践JavaScript - 分割代入で必要な値だけ取り出す

オブジェクトを開いて変数にする

作品オブジェクトから値を使うたびに work.title と書いていくと、同じ work が何度も出てきます。分割代入を使うと、必要な値だけを先に変数として受け取れます。

受け取っていない views はここでは変数になりません。使う値だけを書く、という向きの機能です。

左側に書いたキーと同じ名前の変数が、そのまま作られます。

const work = { title: "旅の記録", year: 2024, views: 1200 }; const { title, year } = work; console.log(title, year); // 旅の記録 2024

1 / 4

入れ子の奥・配列の先頭・名前の付け替え

分割代入で書けるのは1階層だけではありません。奥のオブジェクト、配列の先頭、別の名前での受け取り、そして無かったときの既定値を、1つの式にまとめて書けます。

const work = {
title: "旅の記録",
meta: { author: "sato", year: 2024 },
tags: ["写真", "旅"],
};
const {
title: name,
title: name名前を付け替える
meta: { author },
meta: { author }奥のキーを取る
tags: [firstTag],
tags: [firstTag]配列の先頭を取る
views = 0,
views = 0無かったときの値
} = work;

作られた変数

変数
name旅の記録
authorsato
firstTag写真
views0

囲った行だけが work に無かったキーです。既定値の 0 が入っています。

meta や tags そのものは変数になりません。奥まで書いた行は、通り道ではなく取り出し先だけを作ります。

2 / 4

考えてみよう外しても進めます

work.views に null が入っているとき、const { views = 0 } = work; の views はいくつになりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 分割代入で必要な値だけ取り出す

書き方の早見

分割代入は書き方の組み合わせでできています。1つずつは短いので、対応だけ先に押さえておけば読めるようになります。

いちばん効くのは最後の行です。関数の入口で開いておくと、中では work を1度も書かずに済みます。

やりたいこと書き方
同じ名前で受け取るconst { title } = work
別の名前で受け取るconst { title: name } = work
無いときの既定値const { views = 0 } = work
奥のキーを取るconst { meta: { year } } = work
配列の先頭を取るconst [first] = work.tags
引数で開くfunction card({ title, year }) {}

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript19レッスン

スプレッドとレストで組み替える

導入スライド 4

実践JavaScript - スプレッドとレストで組み替える

既定値の上に受け取った設定を重ねる

設定を受け取る関数では、渡されなかった項目を既定値で埋めることになります。スプレッドで2つのオブジェクトを並べると、後ろに書いたほうの値が勝ちます。

if を並べて1項目ずつ埋める必要はありません。並べる順番が、そのまま優先順位になります。

同じキーがぶつかったときは、後ろに書いたほうが残ります。

const defaults = { published: false, views: 0 }; const input = { title: "旅の記録", published: true }; const work = { ...defaults, ...input }; console.log(work.published); // true

1 / 4

後ろが勝ち、元のデータは変わらない

スプレッドは新しいオブジェクトを作る書き方です。合成した結果がどこから来た値なのかと、元の defaults がどうなっているのかを並べて見ます。

const defaults = { title: "無題", year: 2024, published: false };
const input = { title: "旅の記録", published: true };
const work = { ...defaults, ...input };
...defaults先に敷く
...input後から重ねる
console.log(defaults.title); // 無題
console.log(defaults.title)元は無傷

結果

キーdefaultsinputwork
title無題旅の記録旅の記録
year20242024
publishedfalsetruetrue

囲った2行が input に勝たれた側です。input が持たない year は、defaults の値がそのまま残ります。

defaults の title は 無題 のままです。合成しても元の2つには一切触れていません。

2 / 4

考えてみよう外しても進めます

function tagAll(work, ...tags) {} を tagAll(work) と引数1つで呼ぶと、tags はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - スプレッドとレストで組み替える

3点リーダーの使い分け

同じ ... という記号ですが、左辺に書けばまとめるレスト、右辺に書けば広げるスプレッドになります。よく使う形を並べておきます。

複製されるのは1階層目だけです。work.meta のような入れ子は、複製後も元と同じオブジェクトを指したままなので、そこを書き換えると両方に響きます。

やりたいこと書き方
既定値と合成する{ ...defaults, ...input }
1項目だけ変えた複製{ ...work, views: 1 }
キーを取り除いた残りconst { views, ...rest } = work
配列に継ぎ足す[...work.tags, "新作"]
可変個の引数を受けるfunction f(...args) {}
配列を引数に広げるMath.max(...counts)

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript20レッスン

keys と values と entries

導入スライド 4

実践JavaScript - keys と values と entries

オブジェクトを配列に変える3つ

map や filter はオブジェクトには使えません。そこで、キーだけ・値だけ・両方の組、という3つの形で配列に変えてから配列の道具を使います。

配列にしてしまえば、あとは第3章までで扱った map と filter と reduce がそのまま効きます。

entries だけは、キーと値が2要素の配列に入って返ってきます。

const views = { trip: 1200, night: 800, sketch: 90 }; console.log(Object.keys(views)); // ["trip", "night", "sketch"] console.log(Object.values(views)); // [1200, 800, 90] console.log(Object.entries(views)[0]); // ["trip", 1200]

1 / 4

配列にして絞り、オブジェクトに戻す

閲覧数が100以上の作品だけを残したい、という絞り込みをオブジェクトのまま書くのは面倒です。entries で配列にして filter を通し、fromEntries でオブジェクトの形に戻します。

const views = { trip: 1200, night: 800, sketch: 90 };
const popular = Object.fromEntries(
Object.fromEntriesオブジェクトに戻す
Object.entries(views).filter(([, count]) => count >= 100),
Object.entries(views)配列に変える
filter(([, count]) => count >= 100)組を分割代入で開く
);
// { trip: 1200, night: 800 }

entries の中身

キー100 以上か
trip1200
night800
sketch90

取り消し線の組が filter で落ちるので、戻ってくるオブジェクトは2キーになります。

filter に渡している ([, count]) は前のレッスンの分割代入です。組の2番目だけを名前を付けて受け取っています。

2 / 4

考えてみよう外しても進めます

const byYear = { 2023: 1, 2024: 2 }; のとき、Object.keys(byYear)[0] === 2023 はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - keys と values と entries

変換の早見

行きが keys と values と entries、帰りが fromEntries です。この4つで、オブジェクトと配列を自由に行き来できます。

for-in と違って、いずれも自分のキーだけを返します。取り出した順番は書いた順が保たれますが、数字に見えるキーだけは小さい順に前へ出ます。

やりたいこと書き方
キーの一覧Object.keys(views)
値の一覧Object.values(views)
キーと値の組の一覧Object.entries(views)
組の配列から戻すObject.fromEntries(pairs)
値を合計するObject.values(views).reduce(add, 0)
キーの数を数えるObject.keys(views).length

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript21レッスン

ビット演算でフラグをまとめる

導入スライド 4

実践JavaScript - ビット演算でフラグをまとめる

独立した設定を1つの数値で持つ

公開・注目・新着のように、それぞれが独立して立つ設定があります。真偽値を3つ並べる代わりに、桁を1つずつ割り当てた数値1つで持つ書き方があります。

5 という数字そのものに意味はありません。2進数で見たときに、どの桁が 1 になっているかだけを見ます。

1 と 4 を | でつなぐと、1桁目と3桁目が立った 5 になります。

const PUBLISHED = 1; // 001 const FEATURED = 2; // 010 const NEW = 4; // 100 let flags = PUBLISHED | NEW; console.log(flags); // 5

1 / 4

実践JavaScript - ビット演算でフラグをまとめる

マスクの1が並んだ桁だけが動く

演算を AND・OR・XOR と切り替えながら、マスクの値を動かしてください。

  • AND はマスクの 1 の桁だけを残す。マスクを 0 まで下げると何も残らない
  • OR はマスクの 1 の桁を立てる。マスクを 255 にすると8桁すべてが立つ
  • XOR はマスクの 1 の桁だけを裏返す。x の 1 は 0 に、0 は 1 になる
ビットマスクで見る・立てる・反転する

2 / 4

考えてみよう外しても進めます

flags が PUBLISHED | NEW で 5 のとき、flags & FEATURED の結果は何になりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - ビット演算でフラグをまとめる

立てる・降ろす・切り替える

フラグに対してやりたいことは4つしかありません。それぞれに演算子が1つずつ対応しているので、対応表として覚えてしまうのが早いです。

降ろすときだけ ~ が要ります。~FEATURED は FEATURED の桁だけが 0 で他は全部 1 の数値なので、AND を取るとその桁だけが落ちます。扱えるのは32桁までです。

やりたいこと書き方
立てるflags = flags | FEATURED
降ろすflags = flags & ~FEATURED
切り替えるflags = flags ^ FEATURED
立っているか調べる(flags & FEATURED) !== 0
まとめて立てるflags | (FEATURED | NEW)
全部降ろすflags = 0

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript22レッスン

第4章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript23レッスン

クラスとインスタンス

導入スライド 4

実践JavaScript - クラスとインスタンス

作品の設計図を class で書く

作品1件は、タイトルとタグというデータと、表示用の文字を作る処理でできています。この組み合わせを毎回ばらばらに書くかわりに、class で1つの設計図にまとめます。new を書くと、その設計図から実物が1つ作られます。

class そのものは設計図なので、書いただけでは何も存在しません。実物が現れるのは new を書いた瞬間です。

constructor が受け取った値を this に置き、label がその this を読んでいます。

class Work { constructor(title, tag) { this.title = title; this.tag = tag; } label() { return this.title + " / " + this.tag; } } const work = new Work("ECサイト", "React"); console.log(work.label()); // ECサイト / React

1 / 4

素のオブジェクトの配列をインスタンスの配列に変える

API から返ってくるのは、ただのオブジェクトが並んだ配列です。map で1件ずつ new に通すと、同じ並びのまま、処理を持った作品の配列になります。

const raw = [
rawただの入れ物
{ title: "ECサイト", tag: "React" },
{ title: "分析基盤", tag: "Python" },
];
const works = raw.map(
(r) => new Work(r.title, r.tag),
new Work(r.title, r.tag)1件ずつ実物にする
);
console.log(works[0].label());
works[0].label()処理が生えている

works の中身

添字何になったかlabel() の返り値
0Work のインスタンスECサイト / React
1Work のインスタンス分析基盤 / Python

件数も並び順も raw のままです。変わったのは、1件ずつが処理を持つようになったことだけです。

この変換を入口で1回やっておくと、以降の画面は work.label() と書くだけで済みます。表示の組み立て方があちこちに散らばりません。

2 / 4

考えてみよう外しても進めます

new を通していない素のオブジェクトにも title と tag は入っています。それに対して label() を呼ぶと、どうなると思いますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - クラスとインスタンス

設計図と実物の言い分け

クラスまわりの言葉は、どれも「設計図の側か、実物の側か」で整理できます。ここを取り違えると、あとの継承や static の話がずれていきます。

データと、そのデータを使う処理が同じ場所にある。これが素のオブジェクトとの一番大きな差です。

言葉指しているもの
クラス設計図。Work という書いたものそのもの
インスタンスnew で作られた実物。1件ぶんの作品
constructornew のときに1度だけ走る初期化の処理
thisいま扱っている実物1件
メソッドclass の中に書いた、実物から呼べる処理
プロパティthis に置いたデータ

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript24レッスン

private フィールドとアクセサ

導入スライド 4

実践JavaScript - private フィールドとアクセサ

外から触られたくない値に # を付ける

表示回数のように、勝手に書き換えられると困る値があります。名前の先頭に # を付けたフィールドは、その class の中からしか読み書きできません。外から見せたいときは get を1つ用意して、読む窓口だけを開けます。

読めるけれど書けない、という状態がこれで作れます。work.views に代入すると、set が無いので strict mode ではその場で TypeError になります。

work.views は括弧なしで読めます。中では #views を返しているだけです。

class Work { #views = 0; constructor(title) { this.title = title; } get views() { return this.#views; } } const work = new Work("ECサイト"); console.log(work.views); // 0

1 / 4

書き換えはメソッドを窓口にして、成否を返す

増やす操作もメソッド1つに寄せます。中で値を確かめてから足し、受け付けたかどうかを true と false で返します。呼んだ側は、その返り値を見て次の処理を決められます。

addViews(n) {
if (!Number.isInteger(n) || n <= 0) {
!Number.isInteger(n) || n <= 0受け付けない条件
return false;
}
this.#views += n;
this.#views += n中からだけ書ける
return true;
return true受け付けたと伝える
}

順に呼んだときの views

呼び出し返り値呼んだあとの views
addViews(3)true3
addViews(-1)false3
addViews(0.5)false3
addViews(2)true5

取り消し線の2回は値に届いていません。false が返っただけで、#views は 3 のままです。

外から直接足せるなら、この確認は素通りできてしまいます。窓口を1つに絞ったからこそ、確認が必ず通る場所になります。

2 / 4

考えてみよう外しても進めます

class の外に work.#views = 999; と書いたファイルを読み込むと、どうなると思いますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - private フィールドとアクセサ

窓口の作り分け

何でも # にすればよいわけではありません。読ませたいのか、書かせたいのか、条件付きで受けたいのかで、外に開ける形を選びます。

守っているのは値そのものではなく、値が変わるときに必ず通る道です。道が1本なら、直す場所も1か所で済みます。

外にさせたいこと用意するもの
読ませるが書かせないget だけを書く
条件を確かめてから書かせる成否を返すメソッドを書く
そのまま読み書きさせる# を付けず普通のプロパティにする
中でしか使わない補助の処理#calc() のようにメソッドにも # を付ける
値の見せ方だけ変えるget で加工した結果を返す

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript25レッスン

継承と super

導入スライド 4

実践JavaScript - 継承と super

extends で受け継ぎ、差分だけを書く

注目作品は、ふつうの作品にキャッチコピーが1つ増えただけのものです。extends を書くと Work の持ち物をそのまま受け継げるので、書き足すのは増えたぶんと、変えたいメソッドだけになります。

title と tag を this に置く処理は1行も書いていません。親に任せて、増えた copy だけを自分で置いています。

super(title, tag) が親の constructor、super.label() が親のメソッドの呼び出しです。

class FeaturedWork extends Work { constructor(title, tag, copy) { super(title, tag); this.copy = copy; } label() { return "注目 " + super.label(); } }

1 / 4

受け継いだものと、上書きしたもの

同じ2件を並べると、継承で何が起きたのかがはっきりします。書いていないメソッドは親のものがそのまま動き、書いたメソッドだけが差し替わっています。

const a = new Work("分析基盤", "Python");
const b = new FeaturedWork(
new FeaturedWork(子のほうを作る
"ECサイト",
"React",
"3か月で作った",
);
console.log(a.label());
console.log(b.label());
b.label()上書きしたほうが動く
console.log(b instanceof Work);
b instanceof Work親としても通る

3行の出力

読む式返ってくる値
a.label()分析基盤 / Python
b.label()注目 ECサイト / React
b.copy3か月で作った
b instanceof Worktrue

b の結果の後ろ半分は、親の label がそのまま作った文字です。頭の「注目 」だけが子の担当です。

上書きしたメソッドの中から super で親を呼べるので、全部を書き直す必要はありません。足したいところだけ足せます。

2 / 4

考えてみよう外しても進めます

子の constructor で super(...) より前に this.copy = copy; と書くと、どうなると思いますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 継承と super

super の使い分け

super は書く場所によって意味が変わります。どちらも親を呼ぶ点は同じですが、呼んでいる相手が違います。

継承は共通部分を1か所に置くための道具です。親を直せば子も一緒に直るぶん、親に何を置くかは慎重に決めます。

書き方呼んでいる相手
super(引数)親の constructor。子の constructor の中だけ
super.メソッド名()親の同名メソッド。上書きした中から呼べる
class 子 extends 親親の持ち物をまるごと受け継ぐ宣言
子 instanceof 親true。子は親としても扱える
何も書かないメソッド親のものがそのまま動く

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript26レッスン

多態と static

導入スライド 4

実践JavaScript - 多態と static

同じ名前のメソッドを種類ごとに用意する

作品の種類で表示を変えたいとき、呼ぶ側で if を書くと、種類が増えるたびにその if を直すことになります。かわりに同じ名前のメソッドを種類ごとに用意しておくと、呼ぶ側は名前を書くだけで済みます。

種類を1つ増やすときに触るのは、新しい class を足すことだけです。呼び出し側のループは書いたまま動きます。

ループの中に種類を見る分岐はありません。どちらが動くかは w 自身が知っています。

class Work { badge() { return "作品"; } } class FeaturedWork extends Work { badge() { return "注目作品"; } } for (const w of [new Work(), new FeaturedWork()]) { console.log(w.badge()); } // 作品 // 注目作品

1 / 4

static は設計図の側に付く

作った件数のように、1件ずつではなく Work 全体で1つあればよい値があります。static を付けたフィールドは設計図の側に置かれ、static のメソッドはインスタンスを作る窓口として使えます。

class Work {
static created = 0;
static created = 0設計図に1つだけ
constructor(title) {
this.title = title;
Work.created += 1;
Work.created += 1作るたびに数える
}
}
class WorkCollection {
constructor(works) {
this.works = works;
}
static fromRaw(raw) {
static fromRaw(raw)作る窓口
return new WorkCollection(
raw.map((r) => new Work(r.title)),
);
}
}
const list = WorkCollection.fromRaw([
{ title: "ECサイト" },
{ title: "分析基盤" },
]);

実行後に読める値

読む式返ってくる値
list.works.length2
Work.created2
list.works[0].titleECサイト
list.works[0].createdundefined

取り消し線の行は、インスタンスから static を読もうとしたものです。設計図の側にしか無いので出てきません。

fromRaw を通せば、生のデータから作る手順が1か所にまとまります。呼ぶ側は new の書き方を知らなくてよくなります。

2 / 4

考えてみよう外しても進めます

作品を10件作ったあと、そのうちの1件を使って work.created を読むと何が返ると思いますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

インスタンス側と設計図側の早見

同じ class の中に書いていても、static が付くかどうかで、どちらに生えるかが変わります。付ける場所を決めるときは「1件ごとに違う値か」を先に考えます。

インスタンス側 (1件ごと)

badge() { ... } // work.badge() のようにインスタンスから呼ぶ this.title = title // 1件ごとに違う値

設計図側 (static が付く)

static fromRaw() { ... } // Work.fromRaw() のように class から呼ぶ static created = 0 // Work 全体で1つの値 static の中の this // その class 自身を指す

同じ名前のメソッドを並べて if を消し、全体で1つの値は static に置く。この2つで、種類が増えても直す場所が増えなくなります。

4 / 4

実践JavaScriptのコースサムネイル導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript28レッスン

第5章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript29レッスン

try catch finally

導入スライド 4

実践JavaScript - try catch finally

失敗するかもしれない処理を囲む

保存しておいた作品データを読み直すとき、中身が壊れていれば JSON.parse はそこで止まります。止まってもページ全体を巻き込まないように、失敗しうる処理だけを try で囲み、失敗したときの動きを catch に書きます。

この raw が壊れた文字列だったとき、どの行まで進んでどこへ飛ぶのかを次の図解で追います。

成功しても失敗しても、最後の finally だけは必ず通ります。

const raw = '[{"title":"作品A"},{"title":"作品B"}]'; try { const works = JSON.parse(raw); console.log(works.length); // 2 } catch (error) { console.log("作品データを読み込めませんでした"); } finally { console.log("読み込みを終えました"); }

1 / 4

実践JavaScript - try catch finally

失敗したあと処理がどこへ行くか

値を切り替えて、try を抜けるか受け止められるかを追ってください。図解の except は JavaScript の catch にあたります。

  • 失敗する値にすると、その行で止まって下の行は実行されない
  • 受け止める側の型を合わせておくと、プログラムは止まらず最後の箱まで進む
  • 型をずらすと受け止められず、経路が図の外へ抜けてプログラムが止まる
try と except のルート

2 / 4

考えてみよう外しても進めます

try の中で処理が途中で止まって catch に入ったとき、finally のブロックはどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - try catch finally

3 つのブロックに何を書くか

try に何でも詰め込むと、どの行が失敗したのか分からなくなります。囲むのは失敗しうる処理だけにして、残りは外へ出します。

catch を空にすると、動いているように見えて中身が空のまま進みます。受け止めたなら、代わりに何をするかを必ず書きます。

書く場所そこに書くこと
try失敗するかもしれない処理だけ
catch (error)失敗したときの代わりの動き
finally成功しても失敗しても通る後始末
error.message何が起きたのかの説明文
catch の中を空にする失敗が消える。原因を追えなくなる

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript30レッスン

自分でエラーを投げる

導入スライド 4

実践JavaScript - 自分でエラーを投げる

おかしな値のまま先へ進ませない

作品一覧から目当ての 1 件を探して見つからなかったとき、undefined をそのまま返すと、困るのは受け取った側の少し先です。throw を書くと、その場で処理が止まって呼び出し元に伝わります。

ただし Error のままだと、受け取った側は「何かに失敗した」としか分かりません。失敗の種類を名前で表す方法を次の枚で見ます。

throw より下の return は実行されません。関数はそこで終わります。

function findWork(works, id) { const work = works.find((w) => w.id === id); if (!work) { throw new Error("作品が見つかりません"); } return work; } const works = [{ id: 1, title: "作品A" }]; findWork(works, 7); // ここで止まる

1 / 4

失敗の種類を自前のクラスで表す

Error を継承したクラスを作ると、失敗に名前が付きます。探していた id のような手掛かりも一緒に持たせられるので、受け取った側が判断できるようになります。

class WorkNotFoundError extends Error {
extends ErrorError を受け継ぐ
constructor(id) {
super("作品 " + id + " が見つかりません");
this.name = "WorkNotFoundError";
this.name失敗の種類の名前
this.id = id;
this.id = id手掛かりを持たせる
}
}
throw new WorkNotFoundError(7);

catch (error) の中で調べると

書いたこと返る値
error instanceof WorkNotFoundErrortrue
error instanceof Errortrue
error.nameWorkNotFoundError
error.message作品 7 が見つかりません
error.id7

囲った行は自前のクラスだから取れるものです。ただの Error には id がありません。

Error を継承しているので、既存の catch はそのまま受け取れます。増えたのは、見分けるための手掛かりだけです。

2 / 4

考えてみよう外しても進めます

自前の WorkNotFoundError を投げたとき、catch (error) と書いただけのブロックで受け取れますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 自分でエラーを投げる

投げるときの書き分け

throw できるのは Error だけではありませんが、文字列を投げると受け取った側で message も stack も取れません。投げるものは Error か、その子孫にそろえます。

投げるかどうかの目安は、その場で決められるかどうかです。代わりの動きをその場で書けるなら catch で受け止め、書けないなら投げて呼び出し元に任せます。

やりたいこと書き方
処理を止めて呼び出し元に知らせるthrow new Error('説明')
失敗の種類を分けるclass XxxError extends Error
受け取った側で種類を見るerror instanceof XxxError
元の失敗も一緒に運ぶnew Error('説明', { cause: error })
どこも受け取らなかったとき上へ伝わり続け、最後は処理が止まる

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript31レッスン

失敗を画面に出す

導入スライド 4

実践JavaScript - 失敗を画面に出す

コンソールで終わらせない

作品一覧の取得に失敗したとき、console.error だけ書いて終わると、画面は空のまま止まって見えます。catch で受け取った失敗を、利用者が読める文言として決まった場所に出します。

先頭の hidden = true が、前回の失敗の文言を消す役です。ここが無いと、次に成功しても文言が残ります。

文言を出す場所は #error の 1 か所に決めて、読み込みを始めるたびに隠し直します。

async function showWorks() { const box = document.querySelector("#error"); box.hidden = true; try { const works = await fetchWorks(); render(works); } catch (error) { box.textContent = "作品を読み込めませんでした"; box.hidden = false; console.error(error); } }

1 / 4

画面向けの文言と、開発者向けの記録を分ける

失敗の種類が分かるときだけ言い換えて、それ以外は共通の文言でまとめます。原因そのものは画面には出さず、console.error に元のエラーを渡して残します。

catch (error) {
const text =
error instanceof WorkNotFoundError
error instanceof WorkNotFoundError失敗の種類を見る
? "その作品は公開を終了しました"
: "作品を読み込めませんでした";
box.textContent = text;
box.textContent = text決まった場所に出す
box.hidden = false;
console.error(error);
console.error(error)原因は開発者向けに残す
}

結果

起きたこと画面に出る文言コンソールに残るもの
作品が見つからないその作品は公開を終了しましたWorkNotFoundError
通信に失敗した作品を読み込めませんでしたTypeError
JSON が壊れていた作品を読み込めませんでしたSyntaxError

画面の文言は 2 種類でも、コンソールには起きたことがそのまま残ります。

利用者に伝えるのは次に何ができるかだけです。関数名やファイル名は読んでも役に立たず、出す側の作りを外に見せることにもなります。

2 / 4

考えてみよう外しても進めます

読み込みに失敗して文言を出したあと、もう一度読み込んで今度は成功しました。前の文言はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 失敗を画面に出す

画面に出すときに先に決めること

失敗のたびに場所と文言を考えていると、画面ごとに出方がばらつきます。次の 5 つを最初に決めておけば、あとは同じ形で書けます。

問い合わせフォームの送信も同じ形です。送信を押した時点で文言を隠し、失敗したら同じ場所に出す。画面が変わっても手順は変えません。

決めること決め方
どこに出すか先に置いた 1 か所。毎回同じ場所
何を出すか次にできることが分かる短い文言
いつ消すか次の読み込みを始めるとき
原因をどこに残すかconsole.error に元のエラーを渡す
出してはいけないものスタックトレースや通信先の URL

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript32レッスン

第6章まとめクイズ

導入スライド未作成
実践JavaScriptのコースサムネイル
実践JavaScript33レッスン

正規表現のきほん

導入スライド 4

実践JavaScript - 正規表現のきほん

文字ではなく形で探す

作品の説明文から日付を取り出したいとき、探すのは特定の文字列ではありません。数字 4 つ、ハイフン、数字 2 つ、という形です。この形を書いたものが正規表現です。

この {4} や {2} の数字を動かすと、当たる場所がどう変わるのかを次の図解で確かめます。

2024 という文字を探しているのではなく、数字が 4 つ続く場所を探しています。

const text = "作品公開日 2024-05-01 更新日 2024-11-20"; const found = text.match(/\d{4}-\d{2}-\d{2}/); console.log(found[0]); // "2024-05-01"

1 / 4

実践JavaScript - 正規表現のきほん

式を変えると当たる場所が変わる

式を切り替えたり n を動かしたりして、帯がどこに乗るか数えてください。

  • 帯が乗るのが当たった場所。破線で囲まれたほうは取りこぼしている
  • n をどこに動かしてもマッチ数が 2 にならない。桁を決め打ちすると片方しか拾えない
  • 桁数を決めない式に切り替えると、形の違う両方に帯が乗る
正規表現がどこに当たるか

2 / 4

考えてみよう外しても進めます

作品IDが W7 と W12 のように桁数がまちまちです。/W\d{2}/ でどちらも取り出せますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 正規表現のきほん

文字クラスと量指定子の早見

正規表現は、どんな文字かを表す部分と、それが何回続くかを表す部分の組み合わせでできています。この 2 つが読めれば、たいていの式は追えます。

match は当たった文字列を配列で返し、0 番目が当たった部分そのものです。当たらなければ null が返るので、取り出す前に確かめます。

書き方意味
\d数字 1 文字
\w英数字とアンダースコア 1 文字
[a-z]その範囲のどれか 1 文字
{2}直前をちょうど 2 回
+直前を 1 回以上
?直前を 0 回か 1 回

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript34レッスン

入力を検証する

導入スライド 4

実践JavaScript - 入力を検証する

^ と $ で全体を縛る

作品IDが W から始まって数字 3 桁で終わる、という決まりを式にします。^ と $ を書かないと、長い文字列のどこかに当たっただけで通ってしまうので、全体の形を見たいときは必ず両端を縛ります。

3 つ目が false になるのが ^ の効き目です。^ が無ければ、途中にある W012 に当たって true になります。

test は当たったかどうかだけを true か false で返します。取り出しはしません。

const idPattern = /^W\d{3}$/; console.log(idPattern.test("W012")); // true console.log(idPattern.test("W12")); // false console.log(idPattern.test("aW012")); // false

1 / 4

問い合わせフォームの入力を判定する

フォームの項目ごとに式を持たせておくと、判定は 1 つの関数で済みます。メールアドレスの式は、@ と空白以外が並んで、@ があって、ドットがある、という最低限にとどめます。

const rules = {
name: /^.{1,20}$/,
/^.{1,20}$/全体で 1 から 20 文字
email: /^[^@\s]+@[^@\s]+\.[^@\s]+$/,
[^@\s]+@ と空白以外が 1 文字以上
\.ドットそのもの
};
function validate(field, value) {
return rules[field].test(value);
}

validate('email', 入力)

入力された値返る値
tanaka@example.comtrue
tanaka@examplefalse
tanaka example.comfalse
a@b.ctrue

囲った a@b.c も true です。形として成り立っているからで、式は嘘をついていません。

取り消し線の 2 行はドットが無い、あるいは @ が無いので落ちます。式が見ているのはそこまでです。

2 / 4

考えてみよう外しても進めます

メールアドレスが本当に使えるものかどうかを、正規表現だけで判定しきれますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 入力を検証する

検証でよく使う書き方

フォームの検証で書く式は、そう何種類もありません。全体を縛る書き方と、文字数を決める書き方を押さえれば、あとは項目ごとの組み合わせです。

厳しすぎる式は、正しい入力を弾いて問い合わせそのものを取りこぼします。迷ったら緩めに書いて、あとの工程で確かめるほうが損が小さくなります。

やりたいこと書き方
全体を縛る^ で始めて $ で終える
当たるかだけ見るpattern.test(value)
文字数を決める{3,} や {1,20}
その文字以外[^@\s]
空白だけの入力を弾く^\s*$ に当たったら空とみなす
大文字と小文字を区別しない式の末尾に i を付ける

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript35レッスン

置換とキャプチャ

導入スライド 4

実践JavaScript - 置換とキャプチャ

当たった部分を書き換える

フォームに貼り付けられた作品名には、余分な空白や改行が混ざります。replace は当たった部分を別の文字列に差し替えるので、空白の連続を 1 つにそろえる用途にそのまま使えます。

末尾の g が「当たった全部」の指定です。これが無いと最初の 1 か所しか置き換わりません。

元の title は変わりません。書き換えた新しい文字列が返ってきます。

const title = "作品名 ポートフォリオ サイト"; console.log(title.replace(/\s+/g, " ")); // "作品名 ポートフォリオ サイト"

1 / 4

かっこで囲った部分を取り出して使う

式の一部をかっこで囲むと、そこに当たった部分を置換先で $1 として使えます。番号は左のかっこから順です。差し込むだけでなく加工が要るときは、置換先に関数を渡します。

const raw = "2024-05-01";
const jp = raw.replace(/(\d{4})-(\d{2})-(\d{2})/, "$1年$2月$3日");
(\d{4})1 つ目のかっこ
$1年$2月$3日かっこの中身を順に差し込む
const masked = "tanaka@example.com".replace(
/^(.).+(@.+)$/,
(all, head, domain) => head + "****" + domain,
(all, head, domain)加工が要るなら関数
);

結果

元の値書き換えた結果
2024-05-012024年05月01日
tanaka@example.comt****@example.com

囲った行は関数を渡したほうです。先頭 1 文字とドメインだけを残して、間を伏せています。

関数の第 1 引数は当たった部分そのもの、2 つ目から先がかっこに当たった部分です。返した文字列が、そのまま置換先になります。

2 / 4

考えてみよう外しても進めます

replace(/\s+/, " ") と g を付けずに書いたとき、空白の連続が 3 か所ある文字列はどうなりますか。

選ぶと、この枚の中で答えと理由を確かめられます。

3 / 4

実践JavaScript - 置換とキャプチャ

置換の書き方の早見

置換先に書けるのは、ただの文字列だけではありません。当たった部分を差し込む記法と、関数を渡す書き方を知っておくと、たいていの整形はこれ 1 つで済みます。

置換先に $ を書く方法と関数を渡す方法、どちらでも足りないほど込み入ってきたら、いったん match で取り出してから組み立て直すほうが読めます。

やりたいこと書き方
最初の 1 件だけreplace(/式/, '置換')
当たった全部replace(/式/g, '置換')
当たった部分そのもの$& を置換先に書く
かっこに当たった部分$1 $2 と番号で書く
かっこに名前を付ける(?<year>\d{4}) と書いて $<year>
計算してから入れる第 2 引数に関数を渡す

4 / 4

実践JavaScriptのコースサムネイル
実践JavaScript36レッスン

第7章まとめクイズ

導入スライド未作成