はじめに
JavaScriptのmap()メソッドを使って空文字の要素をスキップする処理が書きたかったのですが、map()メソッドの使い方に誤解があり、躓いてしまいました。
この経験を記録として残しておきます。
やろうとしていたこと
const FRUITS_LIST = ["りんご", "みかん", "ばなな", "", "ブドウ", ""];
このような配列があったとします。
配列に空文字が含まれてしまっているので、空文字をスキップして、全てカタカナの果物のみの配列にしたいと思っていました。
つまり、以下のような結果を期待していました。
['リンゴ', 'ミカン', 'バナナ', 'ブドウ']
最初に書いていたコード
最初、このようにコーディングしておりました。
const FRUITS_LIST = ["りんご", "みかん", "ばなな", "", "ブドウ", ""];
// カタカナに変換する関数
const formatFruit = (fruit) => {
return fruit.replace(/[\u3041-\u3096]/g, function(match) {
var chr = match.charCodeAt(0) + 0x60;
return String.fromCharCode(chr);
});
};
const FORMAT_FRUITS = FRUITS_LIST.map((fruit) => fruit !== '' && formatFruit(fruit));
出力された結果
するとこのように意図しないfalseがデータに入ってしまいました。
['リンゴ', 'ミカン', 'バナナ', false, 'ブドウ', false]
問題の原因
以下のコードが原因でした。
const FORMAT_FRUITS = FRUITS_LIST.map((fruit) => fruit !== '' && formatFruit(fruit));
次の2点によりミスが起きたと思うので、1つずつ深掘りします。
- map()メソッドの使い方を理解していなかった
- Reactでの&&による条件付きレンダリングと混同してしまった
1.map()メソッドについて
与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
MDNからの引用です。
ここから、map() メソッドは元の配列の長さと同じ長さの新しい配列を返すということがわかります。
論理積 (&&) はオペランドを左から右に向けて評価し、遭遇した最初の偽値のオペランドを直ちに返します。
こちらもMDNからの引用です。今回のコードで
fruit !== '' && formatFruit(fruit)
fruitが空文字の場合、falseが返されます。
そのため、map()によって空文字がfalseに変換されてしまいました。
2.Reactでの&&による条件付きレンダリングと混同してしまった
Reactでは条件付きレンダリングによく&&をよく使用します。
例えば以下のようなコードです。
{ isAuth && <Profile />}
この場合isAuthがtrueなら、Profileコンポーネントがレンダリングされますが、isAuthがfalseの場合何も表示されません。
ReactのJSXで使われるこの書き方と混同してしまったことが今回の原因だと思います。
修正
filterを使って、条件に合わないものはスキップするように修正しました。
メソッドチェーンを使うと、コードが綺麗に書けます。
const FORMAT_FRUITS = FRUITS_LIST
.filter(fruit => fruit !== '')
.map(fruit => formatFruit(fruit));
参考
ありがとうございました!