JS でのアンチカリー

大家讲道理
大家讲道理オリジナル
2017-08-19 10:33:481706ブラウズ

デカリー化

逆に、デカリー化の役割は、本来は特定のオブジェクトが持つ関数である関数を、どのオブジェクトでも利用できるように、関数の適用範囲を拡張することです。は、以下に与えられる関数です。署名


obj.func(arg1, arg2)


は関数形式に変換されます。署名は次のとおりです。


func(obj, arg1, arg2)


これがアンチカリーの正式な記述です。

たとえば、以下は簡単な実装です:


Function.prototype.uncurrying = function() {    var that = this;    return function() {        return Function.prototype.call.apply(that, arguments);
    }
};function sayHi () {    return "Hello " + this.value +" "+[].slice.call(arguments);
}var sayHiuncurrying=sayHi.uncurrying();
console.log(sayHiuncurrying({value:'world'},"hahaha"));


説明:

  • uncurrying は Function のプロトタイプで定義されたメソッドであるため、このメソッドはすべての関数で使用できます。呼び出し時:sayHiuncurrying=sayHi.uncurrying() なので、uncurrying の this は、sayHi 関数を指します (一般に、プロトタイプ メソッドの this は、プロトタイプ オブジェクトのプロトタイプではなく、呼び出し元のオブジェクトを指します。呼び出し元のオブジェクトは別のものです)。 function. 関数は

    javascript) のオブジェクトでもあります

  • call.apply(that, argument) これを call メソッドのコンテキストとして設定し、前の例では実際に call メソッドに引数を渡します。 SayHi をポイントしているため、sayHiuncurrying が呼び出されます (arg1, arg2, ...) は、sayHi.call (arg1, arg2, ...);

  • sayHi.call (arg1, arg2, ...) と同等です。 call関数はarg1をsayHiのコンテキストとして扱い、arg2,...などの残りのパラメータをsayHiに渡すので、最終的にはarg1.sayHi(arg2,...);と同等になります

  • 、これは、sayHiuncurrying(obj,args) が obj.sayHi (args) と等しいことと同等です。

最後に、反対側から見てみましょう。実際、アンチカリー化は、sayHi(args) の元の形式をsayHiuncurrying(obj,args) に変換することと同じであり、これにより、sayHi の使用範囲が一般化されます。 より抽象的に表現すると、アンカリー化アンチカリー化により、元の x.y(z) 呼び出しを y(x',z) の形式の呼び出しに変換できます。 x' を x またはその他のオブジェクトとすると、関数の使用範囲が広がります。

ユニバーサルデカリング関数

上記の例では、アンカリー化がプロトタイプに書き込まれていますが、これは良くありません。実際には、アンカリー化を別の関数にカプセル化できます。


var uncurrying= function (fn) {    return function () {        var args=[].slice.call(arguments,1);        return fn.apply(arguments[0],args);        
    }    
};


上記の関数は非常に明確で直接的です。 。

使用する場合は、uncurrying を呼び出して既存の関数 fn を渡します。decurrying 関数は新しい関数を返し、新しい関数によって受け入れられる最初の実パラメータは fn の this のコンテキストにバインドされ、他のパラメータが渡されます。 fn をパラメータとして指定します。

つまり、アンチカリーのより一般的な説明は、関数の借用である可能性があります。これは、関数が他のオブジェクトを受け入れて処理できることを意味し、借用による一般化により関数の使用範囲が拡大します。

したがって、アンカリー化のより一般的な使用法は、すべてを自分で実装することなく、JavaScript に組み込まれている他のメソッドを借用することです。

テキストの説明は少し複雑なので、コードを読み続けましょう:


var test="a,b,c";
console.log(test.split(","));var split=uncurrying(String.prototype.split);   //[ 'a', 'b', 'c' ]console.log(split(test,','));                   //[ 'a', 'b', 'c' ]


split=uncurrying(String.prototype.split) 特定の fn を uncurrying、つまり String.prototype.split に渡します。そして、split関数はString.prototype.splitの関数です。関数がsplit(test,',')を呼び出すと、渡される最初のパラメータは分割実行のコンテキストであり、残りのパラメータは、に渡されるパラメータと同等です。オリジナルの String.prototype.split 関数。

別の例を見てください:


var $ = {};
console.log($.push);                          // undefinedvar pushUncurrying = uncurrying(Array.prototype.push);
$.push = function (obj) {
    pushUncurrying(this,obj);
};
$.push('first');
console.log($.length);                        // 1console.log($[0]);                            // firstconsole.log($.hasOwnProperty('length'));      // true


これは、「同様の

jqueryライブラリ」を模倣し、実装時にArrayのpushメソッドを借用します。 オブジェクトにはプッシュ メソッドがないことがわかっているため、console.log(obj.push) は未定義を返します。ネイティブ配列メソッド (JS エンジン) は長さ 属性 と配列メンバーを維持するために使用できます。擬似配列オブジェクト。

同様に、以下を継続できます:


var indexof=uncurrying(Array.prototype.indexOf);
$.indexOf = function (obj) {    return indexof(this,obj);
};
$.push("second");
console.log($.indexOf('first'));              // 0console.log($.indexOf('second'));             // 1console.log($.indexOf('third'));              // -1


たとえば、独自のクラス ライブラリを実装するとき、一部のメソッドがネイティブ メソッドに似ている場合、次の方法でネイティブ メソッドを借用できます。カレーなし。

また、Function.prototype.call/apply メソッドをアンカーリングすることもできます。例:


var call= uncurrying(Function.prototype.call);var fn= function (str) {
    console.log(this.value+str);
};var obj={value:"Foo "};
call(fn, obj,"Bar!");                       // Foo Bar!


このようにして、関数は関数型プログラミング

を使用して、通常の「データ」として非常に柔軟に使用できます。これは一部のクラス ライブラリでよく見られます。 一般的なアンカリー化関数の攻撃

上記のアンカリー化関数は、より思考習慣に沿った、理解しやすいバージョンです。 次に、徹底的に攻撃し、他のいくつかのバージョンを見ていきます。とりわけ、B ボックスが高い場合、アンカリー化は次のように書くこともできます:

var uncurrying= function (fn) {    return function () {        var context=[].shift.call(arguments);        return fn.apply(context,arguments);
    }
};


もちろん、まだ B レベルを改善する必要がある場合は、次のようにすることもできます:


リーリー

以上がJS でのアンチカリーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。