JavaScriptのコリ化


概要
カリングは、複数のパラメータを受信する関数を単一のパラメータ(最初の関数の最初のパラメータ)を受け入れる関数に変え、残りのパラメータを受け入れて結果を返す新しい関数の技術です.
コア思想:マルチパラメータが入ってきた関数を単一パラメータ(または一部パラメータ)関数に分解し、内部から次の単一パラメータ(または一部パラメータ)関数を呼び出して、残りのパラメータを順次処理します.
Styan Stefanov--「JavaScript Pattern」の著者によると、コリメートとは関数を理解して処理する部分的なアプリケーションのことです.
JavaScriptでCurryingを実現
関数の一部だけに渡すパラメータを実現するために呼び出し、残りのパラメータを処理するための関数を返します.この文で説明されている特徴.まず、加算関数addを実現します.
function add(x, y) {
  return x + y
}
私たちは今Curryingのadd関数を実装し、この関数はcurriedAddと命名されると、上記の定義に従って、curriedAddは以下の条件を満たす必要があります.
curriedAdd(1)(3) === 4 // true

var increment = curriedAdd(1)
increment(2) === 3 // true

var addTen = curriedAdd(10)
addTen(2) === 12 // true
以上の条件を満たすcurriedAdd関数は、以下のコードで実装されてもよい.
function curriedAdd(x) {
  return function(y) {
    return x + y
  }
}
もちろん以上の実装にはいくつかの問題があります.一般的ではなく、関数が人によって変更される方法でCurrying化を実現したくないです.
しかし、curriedAddの実装は、Curryingの基礎となるCurrrying遅延求値を実現する特性がJavaScriptにおける作用領域を使用する必要があることを示しており、より分かりやすく説明するには、前回送信されたパラメータを保存するために作用領域(すなわち、クローズド)を使用する必要がある.curriedAddを抽象化すると、次のような関数curryingが得られる.
function currying (fn, ...args1) {
  return function (...args2) {
    return fn(...arg1, ...arg2)
  }
}

var increment = currying(add, 1)
increment(2) === 3 // true

var addTen = currying(add, 10)
addTen(2) === 12 // true
この実装では、currying関数の戻り値は、実際には残りのパラメータを受け取り、計算値をすぐに返す関数である.つまり、その戻り値はCurryingに自動的に返されません.したがって、curryingを再帰的に返した関数も自動的にCurryingとすることができる.
function currying(fn, ...args) {
  if (args.length >= fn.length) {
    return fn(...args)
  }
  
  return function (...args2) {
    return currying(fn, ...args, ...args2)
  }
}
以上の関数は簡単ですが、Curryingの核心思想はすでに実現されました.JavaScriptにおいてよく使用されるライブラリLodashにおけるcurryの方法は、コア思想と以上の違いがあまりない.複数回受信されたパラメータの総数と関数が定義されたときのイメージの数を比較し、受信されたパラメータの数がCurrying関数のイメージの数以上である場合、実行結果に戻り、そうでない場合は引き続きパラメータを受け入れる関数を返す.
Currying応用シーン
パラメータ多重化
不変のパラメータを固定し,パラメータ多重を実現することはCurryingの主な用途の一つである.
ケース1
上記のincrementaddTenのパラメータ多重の一例.add方法に対して、最初のパラメータを10と固定すると、この方法はアキュムレータ10を受け入れる方法になる.
ケース2
対象の種類を判断する.例えば、以下の例:
function isArray (obj) {
  return Object.prototype.toString.call(obk) === '[object Array]'
}

function isNumber (obj) {
  return Object.prototype.toString.call(obj) === '[object Number]'
}

function isString (obj) {
  return Object.prototype.toString.call(obj) === '[object String]' 
}

// Test
isArray([1, 2, 3]) // true
isNumber(123) // true
isString('123') // true
しかしながら、上記のスキームにはそれぞれのタイプが一つの方法を定義する必要があります.ここではbindを使用して拡張することができます.利点は改造後のtoStrを直接使用することができます.
const toStr = Function.prototype.call.bind(Object.prototype.toString)

//        
[1, 2, 3].toString()    // "1,2,3"
'123'.toString()    // "123"
123.toString()        // SyntaxError: Invalid or unexpected token
Object(123).toString()    // "123"

//       toStr
toStr([1, 2, 3])     // "[object Array]"
toStr('123')         // "[object String]"
toStr(123)         // "[object Number]"
toStr(Object(123))    // "[object Number]"
上記の例は、まずFunction.prototype.call関数を使用して、this値を指定した後、.bindは新しい関数を返し、常にObject.prototype.toStringを着信パラメータに設定します.
実行を遅らせる
遅延実行もCurryingの重要な使用シーンであり、同様にObject.prototype.toString.call()およびbindも同様の機能を実現することができる.フロントエンド開発では、一般的なシーンは、ラベルバインディング であり、バインディングの方法としてパラメータを伝達することを考慮している.下記にいくつかのよくある方法を出して、優劣を比較します.
ダタ属性で

通过data属性本质只能传递字符串的数据,如果需要传递复杂对象,只能通过 JSON.stringify(data)来传递满足JSON对象格式的数据,但对更加复杂的对象无法支持。(虽然大多数时候也无需传递复杂对象)

通过bind方法

bind方法和以上实现的currying ,在功能上有极大的相似,在实现上也几乎差不多。可能唯一的不同就是bind方法需要强制绑定context,也就是bind的第一个参数会作为原函数运行时的this指向。而currying不需要此参数。所以使用currying或者bind只是一个取舍问题。

箭头函数

handleOnClick(data))} />

bind context

currying


jsPerf , : > bind > currying > trueCurrying
currying bind , , , bind , 。

Currying

1. Currying

, ,bind Curring

2. Currying

Currying , , 。

JavaScriptHaskellJavaScript Currying , 。

JavaScriptCurrying JavaScript

  1. Currying JavaScript , , 。
  2. Currying
  3. Currying , 。 , Currying

+ , :https://cloud.tencent.com/dev...