九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、私も長く開発をさせていただいてますが、好きなことが仕事にできてホントにありがたい限りです😊✨
そして、そんな私の「プログラムを書く際の心得」として、ひとつ意識しているものがあります。
それが、
コードをなるべく書かない
ということです。
なぜなら、コードが少ないと・・・・・
- バグは少なくなる
- 開発速度が上がる
- コードが見やすくなる(保守しようという気になってもらえる)
からです。(とはいえ、さすがに変数名を1文字だけで書いたりはしませんし、インデックスがついたデータは、コードが増えても一旦変数に入れ替えます。そこはバランスですね😊)
そして、コードを少なくするために好んでよく使うJavaScript
パッケージが今回ご紹介する Lodash.js です。
そこで❗
今回は「コード量を減らす」をテーマにして、私がよく使うLodash
のメソッド7つをご紹介したいと思います。
※ちなみに、Laravel mix
でも初期状態でLodash
を使うようになっています。気になる方は、/resources/js/bootstrap.js
をチェックしてみてくださいね。
「コンビニが近いので、
家のプリンタを使わなくなりました😂」
Lodash.jsのバージョン: 4.17.15
目次
_.find() でコレクションから1件取得する
例えば、以下のようなユーザーのコレクション(オブジェクトの配列)があるとします。
const users = [ { id: 1, name: '太郎' }, { id: 2, name: '次郎' }, { id: 3, name: '三郎' }, { id: 4, name: '四郎' }, { id: 5, name: '五郎' }, ];
この中からid
が1
のもの(=太郎さん)を取得する場合、Lodash
を使うとたった1行コードを書くだけで済みます。
const user = _.find(users, { id: 1 }); // 👈 太郎さんのデータ
これが通常のJavaScript
を使って書くと次のようにループを使うことになるので、どうしてもコードが長くなってしまいます。
let user; for(let i in users) { user = users[i]; if(user.id === 1) { break; } } console.log(user); // 太郎
ちなみに、_.find()
はデータの階層が深くても使えます。
次のデータを見てみましょう。
const users = [ { name: '太郎', emails: [ 'taro.1@example.com', 'taro.2@example.com', ] }, { name: '次郎', emails: [ 'jiro.1@example.com', 'jiro.2@example.com', ] }, { name: '三郎', emails: [ 'saburo.1@example.com', 'saburo.2@example.com', ] } ];
では、この中からメールアドレスがtaro.2@example.com
のデータ(つまり、太郎さん)を取得する場合を見てみましょう。
const user = _.find(users, { emails: ['taro.2@example.com'] });
つまり、元データと同じ構造でパラメータを渡すだけで簡単にデータを取ることが出来るというわけですね。
_.filter()で条件にあうデータだけ取得する
例えば、以下のデータの中から「role」が「owner」のものだけを取得してみましょう。
const users = [ { id: 1, name: '太郎', role: 'admin' }, { id: 2, name: '次郎', role: 'owner' }, // 👈 これ { id: 3, name: '三郎', role: 'user' }, { id: 4, name: '四郎', role: 'owner' }, // 👈 これ { id: 5, name: '五郎', role: 'owner' }, // 👈 これ ];
この場合、_.filter()
を使うとfor()
などのループを使わずに実装することができます。
const owners = _.filter(users, user => { return (user.role === 'owner'); // 「role」が「owner」 });
つまり、条件式がtrue
になるものは残り、false
のものは除外されることになります。
実際に取得できるデータは次のとおりです。
ちなみにES6
にもfilter
があって、同じように使うことができます。
const owners = users.filter(user => { return (user.role === 'owner'); });
ただし、ES6
版のfilter()
で注意が必要なのは、以下のようなオブジェクトには使えないということです。
const users = { 1: '太郎', 2: '次郎', 3: '花子', };
この場合、以下のようにfilter is not a function
というエラーが出ます。
逆にLodash
版の場合は、配列/オブジェクト関係なくどちらでも利用ができます。
const filteredUsers = _.filter(users, (name, id) => { return name.includes('郎'); // 名前に「郎」がつくもの });
_.cloneDeep()で階層が深いデータをコピーする
例えば、以下のように3階層あるデータを完全にコピーする場合を見てみましょう。
const data = { first: { second: { third: [ 'value - 1', 'value - 2', 'value - 3', ] } } };
Lodash
の_.cloenDeep()
ならとてもシンプルにコピーをつくることができます。
const copiedData = _.cloneDeep(data); // 👈 これだけでOK
通常のJavaScript
でデータをコピーする場合には、
- まずJSON化
- そのJSONをパースする
という以下のような方法を使っていましたが、_.cloneDeep()
なら見た目もスッキリしています。
// 通常のJavaScript const copiedData = JSON.parse(JSON.stringify(data)); // もしくは、ES 6 const copiedData = Object.assign({}, data);
ちなみに、以下のように「新しい変数を用意すればいいのでは❓」と考えた方もいらっしゃるかもしれません。
const copiedData = data; // 👈 新しい変数に格納
しかし、この場合、data
に変化があるとcopiedData
も同じ内容に変更されてしまうことになります。
const copiedData = data; // 👈 新しい変数に格納 data.first = 'none'; // 👈 dataだけを変更しても・・・・・ console.log(copiedData); // 👈 copiedDataまで変更されます
実行したコンソール内容はこちらです。
_.chunk()で特定の個数ごとに分割する
例えば、以下のような10件のデータを「3件ごとに分割する」場合です。
const items = [ { id: 1, name: '商品名 - 1' }, { id: 2, name: '商品名 - 2' }, { id: 3, name: '商品名 - 3' }, { id: 4, name: '商品名 - 4' }, { id: 5, name: '商品名 - 5' }, { id: 6, name: '商品名 - 6' }, { id: 7, name: '商品名 - 7' }, { id: 8, name: '商品名 - 8' }, { id: 9, name: '商品名 - 9' }, { id: 10, name: '商品名 - 10' }, ];
実際の例はこうなります。
const chunkedItems = _.chunk(items, 3); // 👈 最大3件ごとに分割
実行したものがこちらです。
なお、なぜ_.chunk()
が重宝するかというとBoostrap(バージョン3)
で段組みをする場合、1行ごとにclass="row"
を挟む必要があるため、一旦_.chunk()
で分割する(つまり1行ごとのデータにグループ化する)必要があるためです。
もちろんデータ量が揃っている場合、class="row"
を挟む必要はありませんが、例えば画像の高さが揃っていない場合、以下のように「引っかかる」場所がでてきます。
(また、<table> ... </table>
内で1行ずつデータがほしいときも便ですね)
では、Vue
を使った例を見てみましょう。
<html> <head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div id="app"> <div class="row" v-for="items in chunkedItems"> <!-- 1行ごとに最大3件ループします --> <div class="col-xs-4" v-for="item in items"> <span v-text="item.id"></span>: <span v-text="item.name"></span> </div> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script> <script> new Vue({ el: '#app', data: { items: [ { id: 1, name: '商品名 - 1' }, { id: 2, name: '商品名 - 2' }, { id: 3, name: '商品名 - 3' }, { id: 4, name: '商品名 - 4' }, { id: 5, name: '商品名 - 5' }, { id: 6, name: '商品名 - 6' }, { id: 7, name: '商品名 - 7' }, { id: 8, name: '商品名 - 8' }, { id: 9, name: '商品名 - 9' }, { id: 10, name: '商品名 - 10' }, ] }, computed: { chunkedItems() { return _.chunk(this.items, 3); } } }); </script> </body> </html>
これを実行すると次のようになります。
なお、Bootstrap 4
ではclass="row"
を省略しても1行ごとに高さを合わせてくれるようです(さすが👍✨)
_.groupBy()でグループ化する
例えば、以下のユーザーを「犬派」「猫派」でグループ化する場合です。
const users = [ { id: 1, name: '太郎', dogOrCat: '犬派' }, // 🐶 { id: 2, name: '次郎', dogOrCat: '猫派' }, // 😺 { id: 3, name: '三郎', dogOrCat: '猫派' }, // 😺 { id: 4, name: '四郎', dogOrCat: '犬派' }, // 🐶 { id: 5, name: '五郎', dogOrCat: '猫派' }, // 😺 ];
Lodash
なら1行でOKです。
const groupedUsers = _.groupBy(users, 'dogOrCat');
これを実行した結果はこうなります。
_.sortBy()で並べ順を変更する
通常Ajaxを使ってデータを取得する場合は、サーバー側で並べ替えをするものですが、取得後に並べ替えをしたい場合もでてきたりします。
そういった場合には_.sortBy()
が便利です。
では、次のユーザーデータを「テストの点数が低い順」で並べ替えてみましょう。
const students = [ { id: 1, name: '太郎', score: 85 }, { id: 2, name: '次郎', score: 98 }, { id: 3, name: '三郎', score: 20 }, { id: 4, name: '四郎', score: 31 }, { id: 5, name: '五郎', score: 68 }, ];
これも1行で実行できます。
const sortedStudents = _.sortBy(students, 'score');
実行結果はこうなります。
そして、逆に「テストの点数が高い順」に並べ替える場合は次のようにreverse()
を追加してください。
const sortedStudents = _.sortBy(students, 'score').reverse();
実行結果はこちらです。
_.padStart()で特定の長さの文字列に変換する
例えば、「111」を必ず7桁の長さにして不足している場合はゼロで埋めて「0000111」としたい場合です。
const str = _.padStart('111', 7, '0'); // 0000111
なお、右側にゼロを埋めたい場合は、_.padEnd()
を使ってください。
const str = _.padEnd('111', 7, '0'); // 1110000
なお、ES 6
にも同じ機能があって、こちらもシンプルにコードを書くことができるのでおすすめです。
const number = '111'; const str = number.padStart(7, '0'); // 0000111
ちなみに昔はこんなカンジで書いてましたね😂
const number = '111'; const str = String('0000000' + number).slice(-7);
おまけ: _.isEmpty()で値が空かどうかをチェックする
_.isEmpty()
もとても便利なのですが私の場合、積極的に利用するのがある特定のケースに限られているので次点としました。
そのケースというのが、「オブジェクトが空かどうかをチェックする」というものです。
JavaScript
は少しクセがあって以下のように比較をしてもfalse
が返ることになります。
const obj = {}; return (obj === {}); // 👈 これは falseになります。
そのため、オブジェクトが空かどうかをチェックするには次のようにキーの数を数えるというやりかたで対応しますが、正直コードが長いのでめんどうだったりします。
return (Object.keys(obj).length === 0);
それが、_.isEmpty()
ならシンプルにチェックできるんですね。
return _.isEmpty(obj); // 👈 とってもシンプル!
おわりに
ということで、今回は使い方によってはコード量を劇的に減らすことができるLodash
の便利なメソッド7つをご紹介しました。
今回はたった7つだけでしたが、Lodash
にはコレ以外もめちゃくちゃたくさんのメソッドがあるので、ぜひ「宝探し✨」的な感覚で便利なものを探してみてくださいね。
ではでは〜❗
「コロナの自粛が空けて
ストリート・ピアノの再開が増えてきました❗」