アシアル情報教育研究所・所長の岡本雄樹です。

先日、シンプルな『ToDoアプリ』を公開しました。

こちらは約50行のJavaScriptで『ToDoアプリ』を実現しているのですが、ローカルストレージにデータを保存する部分は他の用途にも使えそうです。

例えば、メモ帳アプリを造るとき、などです。

しかし、ローカルストレージのキーの名前が「todolist」でハードコードされており、また、同じ記述が複数箇所に記述されているため、流用するときには注意が必要です。

そこで、ToDoアプリの設計を少し見直してみます(リファクタリング)。
具体的にはローカルストレージ周りの記述を一つの『連想配列』にまとめることにしました。

サンプルプロジェクト

ToDoアプリ・連想配列版

連想配列とは

 まず「配列」の仕組みについては入門書や文科省の研修資料にもありますが、変数などに複数の値を格納できる仕組みです。複数の値を持つため、0番目の値、1番目の値、2番目の値などの、キー(添え字)を数値で持っています。

はい、キーを数値で持っているのが配列です。

連想配列のキーは数値ではなく、文字列になります。

以上。

キーが文字列であることのメリット・デメリット

キーが文字列である例を示します

banana:美味しくて剥くのも簡単
melon:美味しいけど切るのが面倒
orange:みかんは手で剥けるけど、、、

キーが文字列になることで、キーに意味を持たせることができます。

メリットはキーとバリューのペアとして情報に意味を持たせることができることです。上手く活用できれば、プログラムやデータの可読性を向上できます。

デメリットは、毎回自分でキーを考える手間があったり、単純なforやwhileの繰り返し文で中身を追いかけられない点です。

連想配列的なファイル形式として「JSON」、
連想配列的なデータベースの仕組みとして「キーバリュー型のデータベース」があり、その中の一つに「ローカスストレージ」があります。

文科省の研修資料には連想配列も登場します。

オブジェクトとは

JavaScriptでは連想配列とオブジェクトは、ほぼ同一です。
あんこエデュケーションでは、同じものとします。

連想配列の値には関数をセットできる

JavaScriptでは変数の値や連想配列の値に関数をセットできます。この仕組みを応用すれば、可読性や保守性の高いプログラムを作れます。

例えば、ローカルストレージにデータを書き込む関数と読み込む関数などを一つの連想配列にまとめることができます。

また、共通で利用する文字列”todolist”も連想配列の値として持たせることで、メモ帳アプリを作りたいときにはそこだけ変えれば対応できるようになります。

リファクタリングとは

ソースコードの中身を改良することです。
読みやすくしたり(可読性)、直しやすくしたり(保守性)します。

あんこエデュケーションにおいては、エンジニアの人に作って貰ったプログラムを、
初心者や他言語のプログラミング言語を学んだ人でも読めるようにしたり(可読性)、
サンプルアプリなので他の用途に転用しやすく(保守性)することを、
リファクタリングとして行っています。

ToDoアプリ・連想配列版のソースコード紹介

HTMLとCSSは殆ど変更無しです。
js/lib.jsにプログラムの一部を移すので、そこだけ修正しています。

index.html


<script src="js/lib.js" defer></script>

js/lib.js

storageという名前の変数をオブジェクト型として用意します。
そして、オブジェクトの要素として”ToDoList”という値や、ローカルストレージへの読み込み、書き込み、削除の関数を代入しています。

関数の中から”ToDoList”という文字列を参照する方法ですが、『this.key』の記述で行っています。
thisは自身のオブジェクトを表します。


// ローカルストレージ操作オブジェクト
let storage = {};
storage.key = "ToDoList";
storage.get= function() {
    let list = localStorage.getItem(this.key);
    if (list === null) {
        return [];
    } else {
        return JSON.parse(list);
    }
}
storage.add = function (item) {
    let list = this.get();
    list.push(item);
    localStorage.setItem(this.key, JSON.stringify(list));
}
storage.delete = function (index) {
    let list = this.get();
    list.splice(index, 1);
    localStorage.setItem(this.key, JSON.stringify(list));
}

js/main.js

ローカルストレージへの操作をjs/lib.jsに追い出したため、メインの処理は約50行だったものが約30行と短くなりました。


// 初期化処理としてToDoを画面に表示
renderToDoList();
// フォームの情報を元にToDoを保存
function addToDo() {
    let input = document.getElementById("name").value;
    if (input === "") {
        return;
    }
    storage.add(input);
    renderToDoList();
    document.getElementById("name").value = "";
}
// ToDoリストをHTML表示する
function renderToDoList() {
    let ul = document.getElementById("ToDoList");
    ul.innerHTML = "";
    ToDoList = storage.get();
    for (let i = 0; i < ToDoList.length; i++) {
        let ToDo = ToDoList[i];
        let li = document.createElement("li");
        li.textContent = ToDo;
        li.dataset.index = i;
        li.addEventListener("click", deleteToDo);
        ul.appendChild(li);
    }
}
// クリックされたToDoを削除する
function deleteToDo() {
    storage.delete(this.dataset.index);
    renderToDoList();
}