前書き
Lodash ライブラリとUnderscoreライブラリは現在どこにでもあり、今日でも非常に効率的な作成方法を使用しているようです。
作成機能を詳しく見て、コードをより読みやすく、保守しやすく、エレガントにする方法を見てみましょう。
基礎
1)独自の基本的なアルゴリズムを作成するつもりはないため、多くのLodash関数について説明します。これにより、私が集中することを提案することに気が散ります。2)Lodashライブラリは多くの開発者によって使用されており、Underscore、その他のライブラリ、または独自のアルゴリズムに問題なく置き換えることができます。
いくつかの簡単な例を見る前に、compose関数が何をするのか、そして必要に応じて独自のcompose関数を実装する方法を正確に見てみましょう。
var compose = function(f, g) {
return function(x) {
return f(g(x));
};
};
これは最も基本的な実装です。注:引数の関数は右から左に実行されます。つまり、右側の関数が最初に実行され、その結果が左側の関数に渡されます。
次に、このコードを見てみましょう。
function reverseAndUpper(str) {
var reversed = reverse(str);
return upperCase(reversed);
}
reverseAndUpper関数は、最初に指定された文字列を反転してから、大文字に変換します。基本的な作成機能を使用して、このコードを書き直すことができます。
var reverseAndUpper = compose(upperCase, reverse);
これで、reverseAndUpper関数を使用できます。
reverseAndUpper(''); //
コードを書くことで同じ結果を得ることができたでしょう:
function reverseAndUpper(str) {
return upperCase(reverse(str));
}
このオプションはよりエレガントに見え、保守と再利用が簡単です。
機能をすばやく設計し、データ処理パイプラインを作成する機能は、外出先でデータを変換する必要があるさまざまな状況で役立ちます。ここで、コレクションを関数に渡すか、コレクションの要素を変換して、すべてのパイプラインステップが完了した後に最大値を返すか、特定の文字列をブール値に変換する必要があると想像してください。作成機能を使用すると、複数の機能を組み合わせて、より複雑な機能を作成できます。
他の関数や引数をいくつでも含めることができる、より柔軟な作成関数を実装しましょう。前に見たcompose関数は、2つの関数でのみ機能し、渡された最初の引数のみを取ります。次のように書き直すことができます。
var compose = function() {
var funcs = Array.prototype.slice.call();
return funcs.reduce(function(f,g) {
return function() {
return f(g.apply(this, ));
};
});
};
このような関数を使用すると、次のようなコードを記述できます。
Var doSometing = compose(upperCase, reverse, doSomethingInitial);
doSomething('foo', 'bar');
作成機能を実装するライブラリはたくさんあります。それがどのように機能するかを理解するには、compose関数が必要です。もちろん、ライブラリによって実装方法は異なります。異なるライブラリの作成関数は同じことを行うため、互換性があります。これで、compose関数の内容が理解できたので、次の例を使用して、Lodashライブラリの_.compose関数を見てみましょう。
の例
簡単に始めましょう:
function notEmpty(str) {
return ! _.isEmpty(str);
}
notEmpty 関数は、_。isEmpty関数によって返される値の否定です。
Lodashライブラリの_.compose関数を使用して同じ結果を得ることができます。関数を書きましょう:
function not(x) { return !x; }
var notEmpty = _.compose(not, _.isEmpty);
これで、notEmpty関数を任意の引数で使用できます。
notEmpty('foo'); // true
notEmpty(''); // false
notEmpty(); // false
notEmpty(null); // false
これは非常に単純な例です。もう少し複雑なものを見てみましょう。findMaxForCollection
関数は、idプロパティとval(value)プロパティを持つオブジェクトのコレクションから最大値を返します。
function findMaxForCollection(data) {
var items = _.pluck(data, 'val');
return Math.max.apply(null, items);
}
var data = [{id: 1, val: 5}, {id: 2, val: 6}, {id: 3, val: 2}];
findMaxForCollection(data);
作成機能を使用して、この問題を解決できます。
var findMaxForCollection = _.compose(function(xs) { return Math.max.apply(null, xs); }, _.pluck);
var data = [{id: 1, val: 5}, {id: 2, val: 6}, {id: 3, val: 2}];
findMaxForCollection(data, 'val'); // 6
ここでやるべきことがあります。
_.pluckは、最初の引数としてコレクションを、2番目の引数としてコールバック関数を想定しています。_.pluck関数を部分的に適用することは可能ですか?この場合、カレーを使用して引数の順序を変更できます。
function pluck(key) {
return function(collection) {
return _.pluck(collection, key);
}
}
findMaxForCollection 関数をもう少し微調整する必要があります。独自のmax関数を作成しましょう。
function max(xs) {
return Math.max.apply(null, xs);
}
これで、作成機能をよりエレガントにすることができます。
var findMaxForCollection = _.compose(max, pluck('val'));
findMaxForCollection(data);
独自のpluck関数を作成し、「val」プロパティでのみ使用できます。 Lodashに既製の便利な関数がすでにある場合、なぜ独自のフェッチメソッドを作成する必要があるのか理解できない場合があります
_.pluck
。問題は_.pluck
、最初の引数としてコレクションを想定していることであり、別の方法で実行したいと考えています。引数の順序を変更することにより、最初の引数としてキーを渡すことにより、関数を部分的に適用できます。返された関数はデータを受け入れます。
サンプリング方法をもう少し洗練することができます。 Lodashには、次の
_.curry
ような関数を記述できる便利なメソッドがあります。
function plucked(key, collection) {
return _.pluck(collection, key);
}
var pluck = _.curry(plucked);
元のpluck関数をラップして、引数を交換します。これで、pluckは、すべての引数を処理するまで関数を返します。最終的なコードがどのようになるか見てみましょう:
function max(xs) {
return Math.max.apply(null, xs);
}
function plucked(key, collection) {
return _.pluck(collection, key);
}
var pluck = _.curry(plucked);
var findMaxForCollection = _.compose(max, pluck('val'));
var data = [{id: 1, val: 5}, {id: 2, val: 6}, {id: 3, val: 2}];
findMaxForCollection(data); // 6
findMaxForCollection 関数は右から左に読み取ることができます。つまり、最初にコレクション内の各アイテムのvalプロパティが関数に渡され、次に受け入れられたすべての値の最大値が返されます。
var findMaxForCollection = _.compose(max, pluck('val'));
このコードは、保守が簡単で、再利用可能で、はるかにエレガントです。最後の例を見てみましょう。機能構成の優雅さをもう一度楽しむためです。
前の例のデータを取得して、activeという新しいプロパティを追加しましょう。これで、データは次のようになります。
var data = [{id: 1, val: 5, active: true},
{id: 2, val: 6, active: false },
{id: 3, val: 2, active: true }];
この関数をgetMaxIdForActiveItems(data)と呼びましょう。オブジェクトのコレクションを取得し、すべてのアクティブなオブジェクトを除外し、フィルタリングされたオブジェクトから最大値を返します。
function getMaxIdForActiveItems(data) {
var filtered = _.filter(data, function(item) {
return item.active === true;
});
var items = _.pluck(filtered, 'val');
return Math.max.apply(null, items);
}
このコードをよりエレガントにできますか?すでにmax関数とpluck関数があるので、フィルターを追加するだけです。
var getMaxIdForActiveItems = _.compose(max, pluck('val'), _.filter);
getMaxIdForActiveItems(data, function(item) {return item.active === true; }); // 5
関数で
_.filter
も同じ問題が発生し_.pluck
ます。最初の引数としてコレクションを想定しているため、この関数を部分的に適用することはできません。初期関数をラップすることにより、フィルター内の引数の順序を変更できます。
function filter(fn) {
return function(arr) {
return arr.filter(fn);
};
}
isActive
オブジェクトを受け取り、アクティブフラグがtrueに設定されているかどうかを確認
する関数を追加しましょう。
function isActive(item) {
return item.active === true;
}
関数
filter
を持つ関数isActive
は部分的に適用できるため、getMaxIdForActiveItems関数にのみデータを渡します。
var getMaxIdForActiveItems = _.compose(max, pluck('val'), filter(isActive));
次に、データを転送する必要があります。
getMaxIdForActiveItems(data); // 5
これで、この関数を書き直して、非アクティブなオブジェクトの中から最大値を見つけて返すようにすることを妨げるものは何もありません。
var isNotActive = _.compose(not, isActive);
var getMaxIdForNonActiveItems = _.compose(max, pluck('val'), filter(isNotActive));
結論
お気づきかもしれませんが、関数の構成は、コードをエレガントで再利用可能なものにするエキサイティングな機能です。主なことはそれを正しく適用することです。
リンク
lodash
ちょっとアンダースコア、あなたはそれを間違っています!(ちょっとアンダースコア、あなたはそれをすべて間違っています!)
@sharifsbeat
続きを読む: