カリー化のコンセプト
- カリー化は関数に関する高次の手法です
- カリー化は関数の変換であり、関数は呼び出されません。関数を変換するだけです。
- これは、
f(a, b)
呼び出し可能な変換からの関数呼び出しを指しますf(a)(b)
- パラメータの一部を関数に渡して呼び出し、残りのパラメータを処理する関数を返すようにします。
// 求和函数
function sum(x, y) {
return x + y;
}
// 进行柯里化
function sumCurry(x) {
// curry(f) 执行柯里化转换
return function(y) {
return x + y;
};
}
// 进行调用
sum(1, 2); // 3
sumCurry(1)(2) // 3
- 実際、sum関数のxパラメーターとyパラメーターは次のように変更されます。
- 最初に関数を使用してxパラメーターを受け取ります
- 次に、yパラメータを処理する関数を返します。
カリー化
しかし、問題は、そのような層をカプセル化することの使用は何ですか?メリットはありません。私たちプログラマーがこれ以上のことをすることは不可能です。この人生では不可能です。
1.パラメータの再利用
- 最初のパラメーターregが再利用されるため、他の場所でhasNumber、hasLetterなどの関数を直接呼び出すことができるため、パラメーターを再利用でき、呼び出すのがより便利になります。
// 正常正则验证字符串 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
2.早めに戻る
- 要約:イベントの監視
- 標準ブラウザ:
元素.addEventListener('事件类型',事件处理函数,冒泡还是捕获);
- IE低バージョン:
元素.attachEvent('事件类型',事件处理函数);
- ここで問題が発生します。つまり、イベントがバインドされるたびに、バインドする前に環境判断が必要になります。
- 上記の機能をカレーすれば、この問題を回避することができます。使用する前に判断してください。
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);
}
}
- 2番目の書き方は、自己実行して新しい関数に戻る最初の書き方に関連しています。このように、毎回判断を避けるためにどの方法を使用するかが実際に事前に決定されます。
3.実行の遅延
// 原始方法
function add() {
var sum = 0, i, len;
for (i = 0, len = arguments.length; i < len; i++) {
sum += arguments[i];
}
return sum;
}
// 将 add 柯里化
var addCurrying = currying(add);
var add123 = addCurrying(1)(2)(3); // 此时只生成了三个方法存于队列中,并未执行
add123(); // 此时才真正的执行计算
- jsでよく使用されるバインドである実装メカニズムはCurryingです。
bind
メソッド:最初のパラメーターを関数実行のコンテキストに設定し、他のパラメーターを呼び出し元のメソッドに順番に渡し(関数自体は実行されないため、実行の遅延と見なすことができます)、動的に作成して返します。新機能
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}
古典的な面接の質問
- 計算結果が次の期待に応えることができるように、addメソッドを実装します。
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(2, 6)(1) = 9;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;