読者です 読者をやめる 読者になる 読者になる

リズムのじかん

javascript、typescriptなど中心に書きます。

ES6で関数をカリー化する関数を書く

pluck

underscore.jsにpluckという関数があります。 この関数は、オブジェクトの配列から指定した属性を取り出した配列を生成します。

pluckの例1

以下のようなキャリアとスマホのデータから、キャリア名を取り出します。

var data = [{
  carrier: 'docomo',
  sp: [{manufacturer: 'sony', product: 'Xperia'}, {manufacturer: 'samsung', product: 'GALAXY'}]
}, {
  carrier: 'au',
  sp: [{manufacturer: '京セラ', product: 'INFOBAR'}, {manufacturer: 'sharp', product: 'AQUOS'}]
}, {
  carrier: 'softbank',
  sp: [{manufacturer: 'sharp', product: 'AQUOS'}, {manufacturer: 'Apple', product: 'iPhone'}]
}];

_.pluck(data, 'carrier'); 
// -> ["docomo", "au", "softbank"]

pluckの例2

スマホの製品名を取り出して重複を省きます。

_.uniq(_.pluck(_.flatten(_.pluck(data, 'sp')), 'product'))
// -> ["Xperia", "GALAXY", "INFOBAR", "AQUOS", "iPhone"]

underscoreの関数に馴染みがない人は以下を参照してください。

http://underscorejs.org

※「括弧が多くて見づらいから関数合成使って」というご指摘はごもっともですが、今はお待ちください。

pluckをカリー化する

  • 例で使用した○○を取り出す関数を複数箇所で使うので共通化したい。
  • 例では日本のデータを使用しているが、海外のデータもある。データを引数に取るようにしたい。

などの理由で、pluckをカリー化して共通化します。

// 引数を2つ取る関数を右からカリー化する関数
var curry2 = function (fun) {
  return function (arg2) {
    return function (arg1) {
      return fun(arg1, arg2);
    };
  };
};

var pluck = curry2(_.pluck); // _.pluckをカリー化
var pluckCarrier = pluck("carrier"); // キャリアを取り出す関数
var pluckSp = pluck("sp") // スマホを取り出す関数

// 使用例:データからキャリアを取り出す
pluckCarrier(data)
// -> ["docomo", "au", "softbank"]

カリー化する関数をES6で書く

本題です。本題は1行だけで済むのですが、なんかさみしかったので、長々と書きました。すみません。

// ES6
var curry2 = fun => arg2 => arg1 => fun(arg1, arg2);

「これだ!!」感がありますよね(・∀・)

BabelでES5へ変換すると、上で書いたcurry2と全く同じものができます。

Babel · The transpiler for writing next generation JavaScript

ちなみにtypescriptとcoffeescriptでも同じように書けました。

おまけ

例2をカリー化と関数合成を使って書くと以下のようになります。

var curry2 = fun => arg2 => arg1 => fun(arg1, arg2);
var pluck = curry2(_.pluck);
var products = _.compose(_.uniq, pluck('product'), _.flatten, pluck('sp'));
products(data);
// -> ["Xperia", "GALAXY", "INFOBAR", "AQUOS", "iPhone"]