関連する推奨事項: 「JavaScript ビデオ チュートリアル 」
最近、コミュニティのテクノロジー ブログを読んでいたときに、偶然 Function Currie を目にしました という単語を変更し、手書きの js 関数カリー化 も要求してください。カリー化とはどのような高度なことなのでしょうか?聞いたことがない?
私は問題を提起し、それを具体的に研究し、いくつかの整理を行いました。
関数カリー化とは何ですか?まず、Wikipedia がどのように説明しているかを見てみましょう:
コンピュータ サイエンスでは、カリー化 (英語: カリー化) は、カリー化またはカリー化とも訳され、複数のパラメーターを受け入れる関数を 1 つのパラメーターを受け入れる関数に変換することです。単一のパラメーター (元の関数の最初のパラメーター) を持つ関数を受け取り、残りのパラメーターを受け入れて結果を返す新しい関数を返します。この手法は、Moses Schönfinkel と Gottlob Frege によって発明されましたが、論理学者の Haskell Gary にちなんで Christopher Strachey によって命名されました。
直観的には、カリー化は「いくつかのパラメーターを修正すると、残りのパラメーターを受け入れる関数が得られる」と述べています。したがって、2 つの変数を持つ関数 y^x の場合、y=2 が固定されている場合、1 つの変数を持つ関数 2^x が得られます。
カリー化の概念は実際には複雑ではありません。わかりやすく言うと、パラメーターの一部を関数に渡して呼び出すだけで、残りは関数を返して処理させるだけです。パラメーター。
テキストの説明がまだ少し抽象的である場合は、add 関数を使用して簡単な関数のカリー実装を作成します。
// 普通的add函数 function add(x, y) { return x + y } // add函数柯里化后 var curryingAdd = function(x) { return function(y) { return x + y; }; }; // 函数复用 var increment = curryingAdd(1); var addTen = curryingAdd(10); increment(2); // 3 addTen(2); // 12
実際、add 関数の x パラメーターと y パラメーターは、最初に関数を使用して x を受け取り、次に y パラメーターを処理する関数を返すように変更されています。ここで、アイデアはより明確になります。つまり、パラメータの一部だけを渡して関数を呼び出し、残りのパラメータを処理する関数を返すようにするということです。
add 関数のカリー化に関する上記の説明を読んだ後、これをカプセル化するのに多大な労力を費やすことに何の意味があるのかという疑問が生じます。
実際、add 関数の最初のカリー化の例には、関数のカリー化によってもたらされる関数の再利用がすでに含まれています。 add 関数のカリー化を通じて、increment 関数と addTen 関数をすばやく実装します。例を見てみましょう:
// 正常正则验证字符串 reg.test(txt) // 函数封装后 function check(reg, txt) { return reg.test(txt) } check(/\d+/g, 'test') //false check(/[a-z]+/g, 'test') //true // Currying后 function curryingCheck(reg) { return function(txt) { return reg.test(txt) } } var hasNumber = curryingCheck(/\d+/g) var hasLetter = curryingCheck(/[a-z]+/g) hasNumber('test1') // true hasNumber('testtest') // false hasLetter('21212') // false
上記の例は通常の検証です。通常、check を直接呼び出します。この関数は問題ありませんが、数字があるかどうかを確認する必要がある場所がたくさんありますが、実際には最初のパラメータ reg を再利用する必要があるため、他の場所で hasNumber、hasLetter、その他の関数を直接呼び出してパラメータを再利用できるようになります。電話。
var on = function(element, event, handler) { if (document.addEventListener) { if (element && event && handler) { element.addEventListener(event, handler, false); } } else { if (element && event && handler) { element.attachEvent('on' + event, handler); } } } var on = (function() { if (document.addEventListener) { return function(element, event, handler) { if (element && event && handler) { element.addEventListener(event, handler, false); } }; } else { return function(element, event, handler) { if (element && event && handler) { element.attachEvent('on' + event, handler); } }; } })();
別の書き方にしたほうが分かりやすいかもしれません上記はまずisSupportパラメータを決定することです
var on = function(isSupport, element, event, handler) { isSupport = isSupport || document.addEventListener; if (isSupport) { return element.addEventListener(event, handler, false); } else { return element.attachEvent('on' + event, handler); } }
プロジェクトを実行するプロセスでは、いくつかの DOM 操作をカプセル化することが非常に一般的です。上記の最初の記述方法も比較的一般的ですが、2 番目の記述方法を見てみましょう。それは比較的異なります。最初の記述方法は、自己実行してから を返すことです。新しい関数は、実際にはどのメソッドを使用するかを事前に決定し、毎回判断することを回避します。
Function.prototype.bind = function (context) { var _this = this var args = Array.prototype.slice.call(arguments, 1) return function() { return _this.apply(context, args) } }
// 初步封装 var currying = function(fn) { // args 获取第一个方法内的全部参数 var args = Array.prototype.slice.call(arguments, 1) return function() { // 将后面方法里的全部参数和args进行合并 var newArgs = args.concat(Array.prototype.slice.call(arguments)) // 把合并后的参数通过apply作为fn的参数并执行 return fn.apply(this, newArgs) } }
// 支持多参数传递 function progressCurrying(fn, args) { var _this = this var len = fn.length; var args = args || []; return function() { var _args = Array.prototype.slice.call(arguments); Array.prototype.push.apply(args, _args); // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数 if (_args.length < len) { return progressCurrying.call(_this, fn, _args); } // 参数收集完毕,则执行fn return fn.apply(this, _args); } }
引数オブジェクトへのアクセスは、通常、名前付きパラメータへのアクセスよりも少し遅くなります。
// 实现一个add方法,使计算结果能够满足如下预期: add(1)(2)(3) = 6; add(1, 2, 3)(4) = 10; add(1)(2)(3)(4)(5) = 15; function add() { // 第一次执行时,定义一个数组专门用来存储所有的参数 var _args = Array.prototype.slice.call(arguments); // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值 var _adder = function() { _args.push(…arguments); return _adder; }; // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回 _adder.toString = function () { return _args.reduce(function (a, b) { return a + b; }); } return _adder; } add(1)(2)(3) // 6 add(1, 2, 3)(4) // 10 add(1)(2)(3)(4)(5) // 15 add(2, 6)(1) // 9
Currying 機能はとても使いやすく、毎日使うのがとても楽しいです。これは、関数型プログラミングを面倒で退屈なものにするために手元に置いておくべき不可欠なツールです。
プログラミング関連の知識について詳しくは、プログラミング入門をご覧ください。 !
以上がJavaScriptにおける関数の合理化について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。