順番に読み進めながら学べます

配列 — 追加・削除・取り出し

複数の商品や作業を 1 つの変数でまとめる配列を、要素の取り出しから追加・削除まで解説します。末尾と先頭への出し入れ、含まれているかの判定、一部の切り出しと差し替えまで押さえます。

カートに入った商品を item1 / item2 / item3 のように別々の変数で持つと、商品が 1 つ増えるたびに変数を足し、件数を数えるコードも書き直す必要があります。配列(複数の値を順番に並べて 1 つの変数で扱うデータ構造)を使うと、何件あっても 1 つの変数で受け取れて、追加や取り消しも配列のメソッドに任せられます。

配列に値を並べる — index と length

配列は [] の中に、値をカンマで区切って並べて作ります。1 つ 1 つの値を 要素(配列に並んでいる値のこと)と呼びます。文字列でも数値でも並べられますが、あとの処理をそろえるため、実務では同じ種類の値を並べます。

並べた要素は index(先頭を 0 として数えた要素の位置)を [] に書いて取り出します。cart[1] = "テープ" と書けば、その位置の要素だけを入れ替えられます。

cart[0] が 1 番目、cart[1] が 2 番目です。1 番目が 0 なので、人が数える順番とは 1 つずれます。

length は要素の個数です。cart.length のように、カッコを付けずに書きます。index は 0 から始まるため、最後の要素の index は length から 1 を引いた値 です。

末尾から数える at(-1) を使うと、length を経由せずに最後の要素を取り出せます。at(-2) なら後ろから 2 番目です。

範囲外の index を読んでもエラーにはならず、値がまだ入っていないことを表す undefined が返ります。

index と length の数え方
cart[0]cart[1]cart[2]"ノート""ペン""テープ"at(-3)at(-2)at(-1)
要素は 3 つなので cart.length は 3、最後の index は 2 です。末尾から数える at(-1) は同じ要素を返します
const cart = ["ノート", "ペン", "テープ"];

console.log(cart[0]);        // ノート
console.log(cart[2]);        // テープ
console.log(cart.length);    // 3

// 末尾は length から 1 を引いた index、または at(-1)
console.log(cart[cart.length - 1]);   // テープ
console.log(cart.at(-1));             // テープ

// 範囲外の index を読んでもエラーにはならない
console.log(cart[5]);        // undefined

末尾と先頭に出し入れする — push / pop / shift / unshift

カートの中身は、商品を足したり取り消したりするたびに変わります。そのたびに配列を書き直していては、件数と index を自分で管理しなければなりません。配列には 末尾と先頭に対して要素を出し入れするメソッド があり、位置の計算はそちらに任せられます。

push(値) は末尾に要素を追加し、追加後の要素数を返します。pop() は末尾の要素を取り除き、取り除いた要素そのもの を返します。

取り消した商品名をそのまま画面に出したいときは、メソッドが返したこの値(返り値)を const removed = cart.pop(); のように変数で受け取ります。

先頭側を扱うのが unshift(値)shift() です。unshift は先頭に追加し、shift は先頭を取り除きます。先頭に 1 つ入れると、それより後ろの要素の index はすべて 1 つずつ後ろへずれます。

4 つのメソッドが触る位置
unshift(値)先頭に追加push(値)末尾に追加配列 cart[ペン, テープ]shift()先頭を取り除くpop()末尾を取り除く
追加する 2 つは追加後の要素数を、取り除く 2 つは取り除いた要素を返します。どれも cart そのものを書き換えます
const cart = ["ペン"];

console.log(cart.push("テープ"));   // 2 (追加後の要素数)
console.log(cart.join(", "));           // ペン, テープ

console.log(cart.pop());                // テープ (取り除いた要素)
console.log(cart.join(", "));           // ペン

cart.unshift("メモ");            // 先頭に追加
console.log(cart.join(", "));           // メモ, ペン

console.log(cart.shift());              // メモ (取り除いた要素)
console.log(cart.join(", "));           // ペン

const で宣言した cart の中身が変わっている点が気になるかもしれません。const が禁止するのは cart = 別の配列 のように 名前に別の値を入れ直すこと で、cart.push(値) のように配列の中身を書き換えることは止めません。この違いが起きる理由は、あとの記事であらためて扱います。

カートに商品を 1 つ足したあと、その商品を取り消すまでの流れを再現します。cart は宣言済みです。

① 万年筆をカートの末尾に追加してください。

② 追加したあとのカートで、末尾にある商品名を表示してください。

③ 追加したあとの商品数を表示してください。

④ 末尾の商品を取り除いて、取り除いた商品名を表示してください。

⑤ 残っているカートの中身を「, 」でつないで表示してください。

(正しく実行できれば解説が表示されます)

JavaScript / TypeScript エディタ

コードを実行してください

作業予定の先頭に、割り込みで入った対応を差し込みます。tasks は宣言済みです。

① 障害対応の一次連絡を、tasks の先頭に追加してください。

② 追加後のタスクを、並んでいる順に「 → 」でつないで表示してください。

③ 先頭のタスクを取り出して、取り出したタスク名を表示してください。

④ 取り出したあとに先頭へ来たタスクを表示してください。

JavaScript / TypeScript エディタ

コードを実行してください

含まれているかを調べる — includes と indexOf

同じ商品をもう一度お気に入りに入れようとしたとき、そのまま push すると同じ名前が 2 つ並びます。追加する前に、その値がすでに配列にあるかどうかを確かめておくと、重複を防げます。

includes(値) は、その値が配列にあれば true、なければ false を返します。位置まで知りたいときは indexOf(値) を使い、最初に見つかった index を返します。見つからないときは -1 です。

文字列の includes / indexOf と考え方は同じで、探す対象が文字ではなく要素です。

どちらも === と同じように型まで見て比べるので、型が違えば別の値として扱います。数値を並べた配列に文字列の "2" を渡しても、一致とは見なされません。

includes と indexOf が返すもの
includes("メモ")配列にあるtrueindexOf("ボード")2 番目にある1indexOf("消しゴム")配列にない-1
お気に入りが ["メモ", "ボード"] のときの返り値です。有無だけが必要なら includes、位置まで必要なら indexOf です。indexOf は見つからないと -1 を返します
const favorites = ["メモ", "ボード"];

console.log(favorites.includes("メモ"));   // true
console.log(favorites.includes("消しゴム"));     // false

console.log(favorites.indexOf("ボード"));  // 1
console.log(favorites.indexOf("消しゴム"));      // -1

// 比べ方は === と同じで、型が違えば別の値
const quantities = [1, 2, 3];
console.log(quantities.includes("2"));            // false

indexOf の結果をそのまま条件に置かない

先頭で見つかったときの indexOf の返り値は 0 です。0 は falsy なので、if (favorites.indexOf(name)) と書くと 先頭の要素だけ「無い」と判定 されます。有無を知りたいだけなら includes を使い、indexOf を使うときは !== -1 のように結果を明示的に比べます。

お気に入りに追加しようとしている商品が、すでに登録済みかどうかを確かめます。favorites / selected / newItem は宣言済みです。

① selected がお気に入りに含まれているかどうかを表示してください。

② newItem がお気に入りに含まれているかどうかを表示してください。

③ selected がお気に入りの何番目にあるかを表示してください。

④ newItem を探したときに返る位置を表示してください。

JavaScript / TypeScript エディタ

コードを実行してください

一部を取り出す・入れ替える — slice と splice

売上ランキングの上位 3 件だけを表示したい、便の一覧の途中の 1 件だけを差し替えたい、といった場面があります。ここで分かれるのは、元の配列を残したまま取り出すのか、元の配列ごと書き換えるのか です。

slice(開始, 終了) は、開始の index から終了の 手前 までを取り出した新しい配列を返します。元の配列は変わりません。

終了を省略すると最後までを取り出します。文字列の slice と数え方は同じです。

splice(開始, 削除数, 追加する値) は元の配列そのものを書き換えます。開始の index から削除数の分だけ取り除き、追加する値を書くとその位置に差し込みます。

返るのは 取り除いた要素の配列 なので、1 件だけ取り除いたときは [0] で中身を読みます。

書き方返す値元の配列
slice(開始, 終了)取り出した新しい配列変わらない
splice(開始, 削除数)取り除いた要素の配列書き換わる
splice(開始, 削除数, 追加する値)取り除いた要素の配列書き換わる
元の配列を書き換えるメソッド・書き換えないメソッド
push末尾に追加unshift先頭に追加splice取り除いて差し込むpop末尾を取り除くshift先頭を取り除くslice取り出すincludes有無を返すindexOf位置を返す元の配列を書き換える元の配列は変わらない
上の 5 つは呼んだ時点で配列そのものが変わります。下の 3 つは元の配列を読むだけ なので、何度呼んでも中身は同じです。
const ranking = ["ペン", "テープ", "メモ", "ボード"];

// slice は新しい配列を返し、ranking は変わらない
const top2 = ranking.slice(0, 2);
console.log(top2.join(", "));       // ペン, テープ
console.log(ranking.length);        // 4

// splice は ranking 自体を書き換える
const removed = ranking.splice(1, 2, "消しゴム");
console.log(removed.join(", "));    // テープ, メモ
console.log(ranking.join(", "));    // ペン, 消しゴム, ボード
console.log(ranking.length);        // 3

slice と splice は 1 文字違いで結果が違う

名前は似ていますが、slice は元の配列を残して新しい配列を返し、splice は元の配列を書き換えます。一覧を表示するためだけに splice を呼ぶと、表示のたびに元のデータが減っていきます。取り出すだけの用途では slice を選びます。

売上ランキングから、表示する範囲を切り出します。ranking は 5 件で宣言済みです。

① 上位 3 件を取り出して、別の変数で受け取ってください。

② 取り出した 3 件を「, 」でつないで表示してください。

③ 4 位以降を取り出して、その件数を表示してください。

④ 元の ranking の件数を表示してください。

JavaScript / TypeScript エディタ

コードを実行してください

配送便の一覧のうち、1 件だけを別の便に差し替えます。shipping は宣言済みです。

① 2 番目に並んでいる便を「夕方の便」に差し替えて、取り除かれた要素を受け取ってください。

② 取り除かれた便の名前を表示してください。

③ 差し替えたあとの一覧を「, 」でつないで表示してください。

④ 差し替えたあとの件数を表示してください。

JavaScript / TypeScript エディタ

コードを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1const items = ["ペン", "テープ", "メモ"]; のとき、length と最後の要素の index の組み合わせはどれですか?

Q2cart.pop() が返す値はどれですか?

Q3呼んでも元の配列が変わらないのはどれですか?