JS で絵文字リストを配列として作る。イテレーターで。
この記事は…
- JS のイテレーターの作り方がわかります
- 絵文字のリストを配列として作れるようになります
- アイデア次第ではもっと実用的な配列もつくれるかもしれません
顔文字のリストがほしくなった
Web サービスを使ってると、絵文字を入力するときに
パレットみたいなのから、選択して入れられる UI ありますよね。
こういうやつ
これを実装するにあたって、一つずつコードに絵文字を打ち込んで、
配列にするのはめんどくさいな…と思いまして。
どうやってラクしようかなと考えたわけです。
イテレーターを作っちゃえば良いのでは?
JS ではイテレーターっていうやつがありまして。
こいつが何なのか、ざっくり言うと
- 何回か繰り返して実行できる関数を、所定のプロパティに持ってるよ
- その関数は実行するたびに、順番に一つずつデータを返すよ
- 終わったら終わりって分かる値を返すよ
というルールを守ってるオブジェクトなんですね。
で、このイテレーター、利点として
返す内容を一つずつ全部詰めた配列をサクッと作れる てのがあるんです。
どれぐらいサクッとかというと、これ一行で 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 = () => ({});
ここは問題ないですね。
アロー関数で空のオブジェクト {}
を返してます。
Symbol.iterator
プロパティを作成
2. const target = () => ({
[Symbol.iterator]: function() {},
});
Symbol.iterator
をキーとするプロパティを作成します。
Symbol.iterator
というのは、シンボルオブジェクトと呼ばれるものですが、
イメージとしては
const target = () => ({
iterator: function() {},
});
とほぼ同じだと思っておいてください。
この形なら、割とよく見る形ですからね。
ただ、ほんとにこの形にしちゃうと、たまたま誰かが同じキー名 iterator
で
プロパティを作ってしまうと、ややこしいことになるので
特別なオブジェクトをキーにして被らないようにしてるんだなーと思っておいてください。
Symbol.iterator
関数がオブジェクトを返すようにする
3. const target = () => ({
[Symbol.iterator]: function() {
return {
next: () => {},
};
},
});
ここでオブジェクトを返すようになりました。
内容は { next: () => {} }
なので、 next
という
キーのプロパティが一個だけあるオブジェクトですね。
next
は関数を返します。
next
が決まった形のオブジェクトを返すようにする
4. const target = () => ({
[Symbol.iterator]: function() {
return {
next: () => {
return {
done: false,
value: 1,
}
},
};
},
});
next
関数が返り値を持ちましたね。
これが結構重要で、この返り値は
{
done: 繰り返しが終わったかどうか(boolean値),
value: 値,
}
この形式である必要があります。
このあたりでお気づきになられた方もいらっしゃるかもしれませんが、
イテレーターというのは、この next
関数を何度も呼んで、
value
部分を都度、その時の値として取り出していくという仕組みなのですね。
で、それを done
が true
になるまで繰り返す、という流れになっています。
ここまで来たらもう少しですね。
next
が途中で done: true
を返すようにする
5. 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
の中でカウンターを増やしていけば、
規定回数で done
が true
になるのも予想できますね。
String.fromCodePoint
でユニコードから絵文字を取得する
6. 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 に表があるので、そちらを確認してもらったら良いかなと。
String.fromCodePoint
を使って、ユニコードを文字にすれば完成です!
結果
並んだ!
Chrome のコンソールで流してみましたが、良好ですね!
もちろん Node.js でもできるので、お好きな環境でどうぞ!
余談
「イテレーターなんか使わなくても普通にループ回して配列に格納していけば良いのでは…?」
「てか、ふつう絵文字の名前でサジェストとかするだろうから、配列じゃなくて辞書型にしないといけないのでは…?」
😶
聞かなかったことにしましょう。
Discussion