JavaScriptでの関数の組み合わせとカリー化を詳しく解説(例付き)

不言
リリース: 2018-10-13 14:43:02
転載
1894 人が閲覧しました

この記事では、JavaScript 関数の組み合わせとカリー化について詳しく説明します (例を示します)。必要な方は参考にしていただければ幸いです。

私たちは皆、オブジェクト指向 SOLID における単一責任原則 (SRP、単一責任原則) を知っています。関数型プログラミングでは、各関数は 1 つの単位であり、実行することは 1 つだけです。しかし、現実の世界は常に複雑であり、現実の世界をプログラミングにマッピングする場合、単一の関数ではあまり意味がありません。このとき、関数の合成とカリー化が必要になります。

チェーン コール

jQuery を使用したことがある場合は、$('.post').eq(1).attr('data などのチェーン コールが何であるかをご存知でしょう。 - test', 'test').JavaScript のネイティブ文字列および配列メソッドの一部は、チェーン呼び出しスタイルを記述することもできます:

'Hello, world!'.split('').reverse().join('') // "!dlrow ,olleH"
ログイン後にコピー

まず第一に、チェーン呼び出しは上記のオブジェクトに基づいています。メソッド splitreversejoin は、前のオブジェクト「Hello, world!」から分離されている場合は再生できません。

関数型プログラミングでは、メソッドはデータから独立しています。関数型の方法で上記を書くことができます。

const split = (tag, xs) => xs.split(tag)
const reverse = xs => xs.reverse()
const join = (tag, xs) => xs.join(tag)

join('',reverse(split('','Hello, world!'))) // "!dlrow ,olleH"
ログイン後にコピー

あなたは間違いなく、冗談だと言うでしょう。これは連鎖呼び出しよりもどのように優れているのでしょうか?これは依然としてデータに依存しています。「Hello, world!」を渡さないと、一連の関数の組み合わせは機能しません。ここでの唯一の利点は、個々のメソッドを再利用できることです。パニックにならないでください。後でコンテンツがたくさんあるので、私が最適化します (愚かにも​​)。変換を進める前に、まず部分適用とカリー化という 2 つの概念を紹介します。

部分アプリケーション

部分アプリケーションは、いくつかのパラメータを受け取り、受け取ったパラメータの少ない関数を返すプロセスです。これはアプリケーションの一部です。 bind を使用して実装します。

const addThreeArg = (x, y, z) => x + y + z;

const addTwoArg = addThreeNumber.bind(null, 1)
const addOneArg = addThreeNumber.bind(null, 1, 2)

addTwoArg(2, 3) // 6
addOneArg(7) // 10
ログイン後にコピー

上記は bind を使用して、残りのパラメーターをそれぞれ受け入れる他の 2 つの関数を生成します。これはアプリケーションの一部です。もちろん、他の方法でも行うことができます。

一部のアプリケーションの問題

一部のアプリケーションの主な問題は、返される関数の型を直接推論できないことです。前述したように、一部のアプリケーションは、返されるパラメーターの数を指定せずに、より少ないパラメーターを受け入れる関数を返します。これは暗黙的なものなので、コードを確認する必要があります。そうして初めて、返された関数が受け取るパラメーターの数がわかります。

カリー化

カリー化の定義: 関数を呼び出すことはできますが、すべてのパラメーターを一度に渡すことはできません。この関数は、次の 1 つの パラメータを受け取る関数を返します。

const add = x => y => x + y
const plusOne = add(1)
plusOne(10) // 11
ログイン後にコピー

カリー化された関数は、パラメーターを 1 つだけ受け取る関数を返し、返される関数の型は予測可能です。

もちろん、実際の開発では、多くの関数はカリー化されていません。いくつかのツール関数を使用して変換できます。

const curry = (fn) => { // fn可以是任何参数的函数
  const arity = fn.length;

  return function $curry(...args) {
    if (args.length < arity) {
      return $curry.bind(null, ...args);
    }

    return fn.call(null, ...args);
  };
};
ログイン後にコピー

オープン ソース ライブラリ Ramda で提供されているカリー メソッドを使用することもできます。

ああ、カレーです。機能は何ですか?

const currySplit = curry((tag, xs) => xs.split(tag))
const split = (tag, xs) => xs.split(tag)

// 我现在需要一个函数去split ","

const splitComma = currySplit(',') //by curry

const splitComma = string => split(',', string)
ログイン後にコピー

カリー関数が新しい関数を生成するとき、それはデータとは何の関係もないことがわかります。新しい関数を生成する 2 つのプロセスを比較すると、カリー化を行わないプロセスは比較的冗長です。

関数の組み合わせ

最初にコードを指定します:

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
ログイン後にコピー

実際、compose は合計 2 つのことを行います:

  1. Receives関数のセット、関数を返します。関数はすぐには実行されません。

  2. 結合関数。渡された関数を左から右に結合します。

一部の学生は上記のreduceRightにあまり慣れていないかもしれません。2元と3元の例を挙げましょう:

const compose = (f, g) => (...args) => f(g(...args))
const compose3 = (f, g, z) => (...args) => f(g(z(...args)))
ログイン後にコピー

関数呼び出しは左から順に行われます。右、データ 左から右への流れも同様です。もちろん、右から左へを定義することはできますが、意味的にはそれほど意味がありません。

さて、最初の例を最適化しましょう:

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const reverseWords = compose(join(''), reverse, split(''))

reverseWords('Hello,world!');
ログイン後にコピー

これははるかにシンプルで理解しやすいでしょうか?ここの reverseWords は、前に説明した Pointfree コード スタイルでもあります。データや外部状態に依存せず、組み合わせた関数です。

Pointfree 前回の記事で JS 関数型プログラミングの概念を紹介し、その利点と欠点についても説明しました。興味のある方はぜひご覧ください。

関数結合の結合法則

まず、小学校の知識の足し算の結合法則: a (b c)=(a b) c を確認しましょう。説明はしませんが、理解できるはずです。

振り返ってみると、実際には関数の組み合わせには結合法則があります。

compose(f, compose(g, h)) === compose(compose(f, g), h);
ログイン後にコピー

これは、関数の組み合わせを自由に組み合わせてキャッシュできるという利点です。

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const getReverseArray = compose(reverse, split(''))

const reverseWords = compose(join(''), getReverseArray)

reverseWords('Hello,world!');
ログイン後にコピー

補足。心理図: ###########################

以上がJavaScriptでの関数の組み合わせとカリー化を詳しく解説(例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!