反不正のトピックは、JavaScript の父であるブレンダン・アイヒ氏の昨年のツイートから来ています。私はここ数日間それについて調べていて、非常に興味深い内容を見つけたので、共有したいと思います。まず名前は忘れて、何ができるかを見てみましょう
この関数を過小評価しないでください。webQQ の ZX ライブラリを例に挙げて、ライブラリを作成するときによくそのようなコードを作成します。
実際に必要なのは、Array プロトタイプ チェーン上のいくつかの関数を借用することです。パラメータを変更して再評価するために新しい関数を明示的に構築する必要はありません。
次のようにアンカリー化メソッドを使用する方が、明らかによりエレガントで美しいです:
また、多くの興味深い便利なことができます。
call メソッドと apply メソッドの両方をアンカリー化することもでき、処理することもできます。関数を通常のデータとして使用します。これにより、JavaScript の関数呼び出しメソッドが以前のスキームに似たものになります。
スキームでの関数呼び出しメソッドは次のようになります。
これは JavaScript で非常によく似た形で書くことができます jquery オブジェクト (つまり、$() によって作成されたオブジェクト) は疑似配列であるため、 jquery オブジェクトにメンバーを追加する必要がある場合、疑似コードは次のようになります。 uncurrying を使用する場合は、を使用できます。
配列オブジェクトのプッシュ関数を借用し、エンジンに配列メンバーと長さのプロパティを自動的に管理させます。 そして、必要な関数をすべて一度に借用できます:。
一般に、アンカリー化テクノロジーを使用すると、どのオブジェクトもネイティブ オブジェクトのメソッドを持つことができます。それでも興味が湧かない場合は、別のことを行ってください。 原理と実装を段階的に見てみましょう。ディカリー化という奇妙な名前を理解する前に、まずカリー化について理解する必要があります。
Wikipedia からの定義: カリー化 (部分評価とも呼ばれる) は、複数のパラメーターを受け入れる関数を 1 つのパラメーターを受け入れる関数に変換し、残りのパラメーターを受け入れて結果を返す新しい関数を返すことです。
簡単に言うと、カリー化は、家を買うときの分割払いの方法に似ています。最初に頭金の一部(パラメータの一部)を渡し、通帳を返し(関数を返します)、その後、残りのパラメータを調べ、必要に応じて計算を評価します。
私たちがよく使っているカリー化を見てみましょう。コンテキストをバインドするときに Function.prototype.bind 関数を実装します。
いわゆる高階関数が実装されます。順序関数は少なくとも次の要件を満たしている必要があります。 2 つの機能: 1、関数はパラメーターとして渡すことができ、2、関数は戻り値として使用できます。
JavaScript は設計の初めに、スキーム言語の多くの機能を参照しました。 Scheme は関数型言語の創始者である Lisp の 2 つの主要な方言の 1 つであるため、JavaScript にも高階関数、クロージャ、ラムダ式などの関数型言語の機能がいくつか備わっています。
JavaScript の関数が別の関数を返すとき、クロージャーが形成され、最初の操作のパラメーターをクロージャーに保存することができます。この考え方を使用して、一般的なカリー化関数を作成します。
パラメータが渡されるとカリー化が続行され、パラメータが空の場合にのみ評価が開始されることに同意します。毎月の支出を計算する関数を毎日の終了前に実装しているとします。今日の出費はいくらかを記録しなければなりませんが、気にするのは月末の合計費用だけであり、毎日計算する必要はありません。カリー化関数を使用すると、計算を最後まで遅らせることができ、多くの場合、不必要な計算を回避でき、遅延評価を実現する解決策にもなります。 、 さて、本題に戻りますが、
curringは、いくつかのパラメータを事前に入力することです
Anti-curringは、将来に渡されるパラメータとして、元の固定パラメータまたはこのコンテキストを遅らせることです
実際には、それはです。そのようなことをするには、次のようにします:
1
obj.foo( arg1 ) //foo は元々 obj のみの関数であるのと同じように、元々は Array.prototype のみにある関数です
この形式に変換されます
1
。 foo( obj, arg1 ) / / 最初に示した例と同じです。 [].push を Push( [] ) に変換します
元々テレビのプラグに接続されていたソケットと同じように、取り外した後は実際には次のようになります。冷蔵庫を接続するために使用されます。
Ecma の Array および String の各プロトタイプ メソッドの後に、push などの段落があります。
注 Push 関数は、意図的に汎用的なものであるため、この値が Array オブジェクトである必要はありません。 concat 関数を適用できるかどうか。まず、動的言語における重要なダック タイピングのアイデアを確認してみましょう。
昔、アヒルの鳴き声を聞くのが好きだった皇帝がいたので、大臣たちを呼んで千羽のアヒルからなる合唱団を結成させました。大臣は国中のアヒルをすべて捕まえましたが、結局一羽がいなくなってしまいました。ある日、ついにボランティアのニワトリがやって来ました。このニワトリも鳴くそうです。 物語の後半で、ニワトリがアヒルの合唱団に紛れ込んでいたことが明らかになります。 - 皇帝はただ鳴き声を聞きたいだけで、あなたがアヒルだろうがニワトリだろうが気にしません。
これはダック タイピングの概念です。JavaScript では、多くの関数はオブジェクトの種類の検出を行わず、これらのオブジェクトが実行できることのみを考慮します。
Array コンストラクターと String コンストラクターのプロトタイプのメソッドは、ダック型になるように特別に設計されています。これらのメソッドは、this のデータ型の検証を実行しません。これが、引数が配列のふりをしてプッシュ メソッドを呼び出すことができる理由です。
v8 エンジンの Array.prototype.push のコードを見てください。 length );
var m = %_ArgumentsLength();
for (var i = 0; i
this[i+n] = %_Arguments(i);
this.length = n + m; //正しい長さ return this.length;}} ご覧のとおり、ArrayPush メソッドは this の型に明示的な制限を課していません。理論上は、この訪問者には任意のオブジェクトを ArrayPush に渡すことができます。 解決しなければならない問題は 1 つだけ残っています。それは、一般的な方法でオブジェクトを配列オブジェクトのふりをする方法です。 実際の実装コードは非常に単純です: このコードは非常に短いですが、最初に理解するのはまだ少し難しいです 何が起こるかを見てみましょう。var Push = Array .prototype.push.uncurrying();
push( obj, 'first' );