Agent Grow Tech Notes
💪

JS で絵文字リストを配列として作る。イテレーターで。

2024/08/16に公開

この記事は…

  • JS のイテレーターの作り方がわかります
  • 絵文字のリストを配列として作れるようになります
  • アイデア次第ではもっと実用的な配列もつくれるかもしれません

顔文字のリストがほしくなった

Web サービスを使ってると、絵文字を入力するときに
パレットみたいなのから、選択して入れられる UI ありますよね。


こういうやつ

これを実装するにあたって、一つずつコードに絵文字を打ち込んで、
配列にするのはめんどくさいな…と思いまして。

どうやってラクしようかなと考えたわけです。

イテレーターを作っちゃえば良いのでは?

JS ではイテレーターっていうやつがありまして。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols#反復可能プロトコル

こいつが何なのか、ざっくり言うと

  • 何回か繰り返して実行できる関数を、所定のプロパティに持ってるよ
  • その関数は実行するたびに、順番に一つずつデータを返すよ
  • 終わったら終わりって分かる値を返すよ

というルールを守ってるオブジェクトなんですね。

で、このイテレーター、利点として
返す内容を一つずつ全部詰めた配列をサクッと作れる てのがあるんです。

どれぐらいサクッとかというと、これ一行で ary に配列入れれるくらいサクッと。

const ary = Array.from(イテレーターオブジェクト);

ということで、
「実行するたびに Unicode の順番で絵文字を返していくイテレーターを作れば、
めっちゃ簡単に絵文字配列が作れるのでは?」
と考えたわけですね。

実践

で、出来上がったのがこちらです。

// ここからイテレーター作成
const target = (start, length) => ({
    [Symbol.iterator]: function() {
        let now = start;

        return {
            next: () => {
                now += 1;
                return {
                    done: start + length === now - 1,
                    value: String.fromCodePoint(0x1F600 + now - 1),
                }
            },
        };
    },
});
// ここまでイテレーター作成

const main = () => {
    const ary = Array.from(target(2, 10));
    console.log(ary);
};

main();

ね?簡単でしょう?

イテレーターの作り方

では、具体的にどんな感じでイテレーターが作られていくか、
上のコードのイテレーター部分の作り方を、順を追って見てみましょうか。

1. 空オブジェクト作成

const target = () => ({});

ここは問題ないですね。
アロー関数で空のオブジェクト {} を返してます。

2. Symbol.iterator プロパティを作成

const target = () => ({
    [Symbol.iterator]: function() {},
});

Symbol.iterator をキーとするプロパティを作成します。

Symbol.iterator というのは、シンボルオブジェクトと呼ばれるものですが、
イメージとしては

const target = () => ({
    iterator: function() {},
});

とほぼ同じだと思っておいてください。
この形なら、割とよく見る形ですからね。

ただ、ほんとにこの形にしちゃうと、たまたま誰かが同じキー名 iterator
プロパティを作ってしまうと、ややこしいことになるので
特別なオブジェクトをキーにして被らないようにしてるんだなーと思っておいてください。

3. Symbol.iterator 関数がオブジェクトを返すようにする

const target = () => ({
    [Symbol.iterator]: function() {

        return {
            next: () => {},
        };
    },
});

ここでオブジェクトを返すようになりました。
内容は { next: () => {} } なので、 next という
キーのプロパティが一個だけあるオブジェクトですね。
next は関数を返します。

4. next が決まった形のオブジェクトを返すようにする

const target = () => ({
    [Symbol.iterator]: function() {

        return {
            next: () => {

                return {
                    done: false,
                    value: 1,
                }
            },
        };
    },
});

next 関数が返り値を持ちましたね。
これが結構重要で、この返り値は

{
  done: 繰り返しが終わったかどうか(boolean値),
  value:,
}

この形式である必要があります。

このあたりでお気づきになられた方もいらっしゃるかもしれませんが、
イテレーターというのは、この next 関数を何度も呼んで、
value 部分を都度、その時の値として取り出していくという仕組みなのですね。

で、それを donetrue になるまで繰り返す、という流れになっています。

ここまで来たらもう少しですね。

5. next が途中で done: true を返すようにする

const target = (start, length) => ({
    [Symbol.iterator]: function() {
        let now = start;

        return {
            next: () => {
                now += 1;
                return {
                    done: start + length === now - 1,
                    value: now - 1,
                }
            },
        };
    },
});

変数類をここで一気に足してしまいましたが、
一つずつ見てもらえば特に不思議なところはないでしょう。

next が何度も呼ばれるということがわかったので、
next の中でカウンターを増やしていけば、
規定回数で donetrue になるのも予想できますね。

6. String.fromCodePoint でユニコードから絵文字を取得する

const target = (start, length) => ({
    [Symbol.iterator]: function() {
        let now = start;

        return {
            next: () => {
                now += 1;
                return {
                    done: start + length === now - 1,
                    value: String.fromCodePoint(0x1F600 + now - 1),
                }
            },
        };
    },
});

仕上げです。
今回はユニコードを使って絵文字を一つずつ取得していくことが目的だったので、
イテレーターが呼ばれるたびに次の絵文字を一つ取得していく形にしてみました。

0x1F600 というのは最初の絵文字のユニコードですね。
このあたりは Wikipedia に表があるので、そちらを確認してもらったら良いかなと。

https://ja.wikipedia.org/wiki/顔文字_(Unicodeのブロック)

String.fromCodePoint を使って、ユニコードを文字にすれば完成です!

結果


並んだ!

Chrome のコンソールで流してみましたが、良好ですね!
もちろん Node.js でもできるので、お好きな環境でどうぞ!

余談

「イテレーターなんか使わなくても普通にループ回して配列に格納していけば良いのでは…?」

「てか、ふつう絵文字の名前でサジェストとかするだろうから、配列じゃなくて辞書型にしないといけないのでは…?」

😶

聞かなかったことにしましょう。

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion