TECHNICAL BLOG

2018/3/22 # JavaScript # フロントエンド 2018/3 lodashのススメ

概要

lodashは軽量なjavascriptのユーティリティライブラリ。
lodash.min.jsをダウンロードしてきてHTMLに埋め込むだけです。

jQueryは$で始まるように、lodashはアンダーバー_から始まります。

何が良いのか?

プレーンな書き方

const items = [];
for(let i = 0; i < max; i++){
    const data = list[i];
    items.push(data.score / 100);
}

const riches = [];
for(let j = 0; j < max; j++){
    const company = companies[j];
    if(company.price < 10000){
        continue;
    }
    riches.push(company);
}

lodashな書き方

const items = _.map(list, (data, index)=>{
    return data.score / 100;
});

const riches = _.filter(companies, (company, index)=>{
    return company.price >= 10000;
});

お分かりいただけるでしょうか。

  • _.map()はreturnされた値で新しい配列を作る
  • _.filter()はreturnがtrueの要素だけ集めた配列を作る(false要素がフィルターされる)

プレーンな書き方と比べるとlodashな書き方は

  • ループする変数名をi, j, kと重複しないように気をつけなくて良い
  • map, filterと何のためのループ処理かわかりやすい
  • 短くかつ分かりやすい

このようにJS側でデータを複雑に加工して利用するために、便利で表現豊かな関数がlodashには数多く揃っています。

  • データを加工したり抽出したりする関数が一通り揃っており生産性も上がる
  • 後から見返したときわかりやすくメンテナンス性がよい

混沌としやすいJSを分かりやすくしてくれます。結果品質を上げてくれるのでオススメなのです。

本家Underscore.js

lodashはUnderscore.jsの派生ライブラリで、Underscore.jsが本家となります。
Underscore.jsもlodashも本番運用で使っていますが、利用できるAPIもほぼ同じで、使い心地もほぼ同じです。
lodashのほうがパフォーマンスがよいと一般的に言われているので今回はlodashを紹介します。(体感上は速度の違いを感じたことはないです)

よく使うlodash関数ベスト4

ベスト1: _.map

配列を引数に渡して、第二引数の関数の戻り値を詰め込んだ新たな配列を生成します。
元の配列は変更されないので、思わぬ影響(バグ)が出ないクリーンなコードになります。

const results = _.map([1, 2, 3], (value, index)=>{
    return value * 3;
});
=> [3, 6, 9]

lodash全般に言えることですが、第二引数の関数の引数は、だいたい第一引数がデータで第二引数がインデックスになります。
また、配列は数値限定ではありません。文字列の配列でもオブジェクトの配列でもなんでも使えます。

ベスト2: _.each

ただのループです。for文と役割は同じで、ただループしたいときに使います。

_.each(['apple', 'orange', 'grape'], (value, index)=>{
    $('div').text(value);
});

ベスト3: _.find

配列の中から条件にあったデータを1つ見つけ出す関数です。
条件は、第二引数の関数の戻り値がtrueのものが1つ抽出されます。

const item = _.find(list, (value, index)=>{
    return value.id == 'xyz';
});
=> {id: 'xyz', date: '2018/2/14', name: 'OSAKA'}

ベスト4: _.filter

_.findとは違い、配列の中から条件にあったデータを全て抽出する関数です。
条件は、第二引数の関数の戻り値がtrueのものが抽出されます。

const results = _.filter([1, 2, 3, 4], (value, index)=>{
    return (value % 2) == 0;
});
=> [2, 4]

こんなこともできるlodash

_.findIndex

複雑なデータの一部だけ書き換えたいときに、たまにインデックス値が欲しくなります。
_.findと違い配列の中から条件にあったデータのインデックスを見つけ出す関数です。

const index = _.findIndex([4, 6, 8, 12], (value, index)=>{
    return value == 8;
});
=> 3

_.keys

オブジェクトを渡すとキー値を得ることができます。
こちらは複雑なデータを整形する場合に、まれに必要になって使います。

_.keys({one: 'taro', two: 'hanako', three: 'jiro'});
=> ["one", "two", "three"]

.first, .initial, .last, .rest

配列の先頭だけ、最後以外、最後だけ、最初以外のデータを得ることができます。
[0]やlength-1などするより分かりやすいですね。

_.first([5, 4, 3, 2, 1]);
=> 5

_.initial([5, 4, 3, 2, 1]);
=> [5, 4, 3, 2]

_.last([5, 4, 3, 2, 1]);
=> 2

_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]

タイマー処理もできるlodash

_.defer

この関数はsetTimeoutを0秒指定した場合と同等の機能になります。
複雑なUIを作っていると、まれに使いたくなる関数です。

_.defer(()=>{
    console.log('0秒非同期!');
});

_.throttle

スクロールやリサイズ、キーイベントなど短時間に大量のイベントが発行されて動作が重くなることがあります。
この関数をそんな時に利用すると、イベントを間引いてくれ動作が軽くなります。
この例ではどんなにスクロールさせても0.8秒毎に1回のみ実行されます。

function onScroll(){
    console.log('スクロール通知');
}
$(window).scroll(_.throttle(onScroll, 800));

_.debounce

こちらもイベントを間引いてくれる関数です。
_.throttleとは違い正確には間引くわけではありません。
この例ではリサイズイベントを受けてから5秒後に1回実行されます。
ただし、5秒以内にリサイズイベントが発行され続けている間は一度も実行されません。
つまり、リサイズイベントが収まってからから1回のみ実行されます。

function onResize(){
    console.log('リサイズ通知');
}
$(window).resize(onResize, 5000);

_.delay

setTimeoutのlodash版の書き方です。

_.delay(()=>{
    console.log('1秒たちました');
}, 1000);

他にも多くの関数が用意されているので、興味の沸いた方はlodashUnderscore.jsに全関数の説明があるので参考にしてみてください。