ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScriptの興味深いアンチカリーを徹底分析_基礎知識

JavaScriptの興味深いアンチカリーを徹底分析_基礎知識

WBOY
リリース: 2016-05-16 17:47:12
オリジナル
1192 人が閲覧しました

写在前面的话:国内对前端的研究在某些方面也不逊色于国外,这篇文章虽然看不太懂,但我很欣赏这种深入研究的精神!

反科里化的话题来自javascript之父Brendan Eich去年的一段twitter. 近几天研究了一下,觉得这个东东非常有意思,分享一下。先忘记它的名字,看下它能做什么.

不要小看这个功能,试想下,我们在写一个库的时候,时常会写这样的代码,拿webQQ的Jx库举例。


我们想要的,其实只是借用Array原型链上的一些函数。并没有必要去显式的构造一个新的函数来改变它们的参数并且重新运算。

如果用uncurrying的方式显然更加优雅和美妙,就像这样:

还能做很多有趣和方便的事情.

甚至还能把call和apply方法都uncurrying,把函数也当作普通数据来使用. 使得javascript中的函数调用方式更像它的前生scheme, 当函数名本身是个变量的时候, 这种调用方法特别方便.

scheme里面调用函数是这样:

javascript里可以写的很接近.

再看看jquery库,由于jquery对象( 即通过$()创建的对象 )是一个对象冒充的伪数组,它有length属性,并且能够通过下标查找对应的元素,当需要给jquery对象添加一个成员时, 伪代码大概是:

如果用uncurrying的话, 就可以

借用了array对象的push函数, 让引擎去自动管理数组成员和length属性.

而且可以一次把需要的函数全部借过来, 一劳永逸. 一段测试代码:

总的来说, 使用uncurrying技术, 可以让任何对象拥有原生对象的方法. 好了,如果到这里依然没有引起你的兴趣,那么你可以去干点别的了。

接下来一步一步来看看原理以及实现。
在了解反currying化这个奇怪的名字之前,我们得先搞清楚currying。

Wikipedia からの定義: カリー化 (部分評価とも呼ばれます) は、複数のパラメーターを受け入れる関数を 1 つのパラメーターを受け入れる関数に変換し、残りのパラメーターを受け入れて結果を返す新しい関数を返すことです。 。

カリー化とは、簡単に言うと、家を買うときの分割払いのようなもので、まず頭金の一部(パラメーターの一部)を渡して、通帳を返して(関数を返して)、その後にお金を渡します。残りのパラメータを調べ、必要に応じて計算を評価します。

コンテキストをバインドするときによく使用するカリー化を見てみましょう。

高階関数はカリー化の基礎です。
1. 関数はパラメーターとして渡すことができます。
2.戻り値。

JavaScript は設計の開始時にスキーム言語の多くの機能を参照しました。 Scheme は関数型言語の創始者である Lisp の 2 つの主要な方言の 1 つであるため、JavaScript にも高階関数、クロージャ、ラムダ式などの関数型言語の機能がいくつか備わっています。

JavaScript の関数が別の関数を返す場合、クロージャーが形成され、最初の操作のパラメーターをクロージャーに保存することができます。この考え方を使用して、一般的なカリー化関数を作成します。

パラメータが渡されるとカリー化が続行され、パラメータが空の場合にのみ評価が開始されることに同意します。

毎月の支出を計算する関数を実装しているとします。毎日の終わり前に、今日費やした金額を記録する必要がありますが、気にするのは月末の合計コストだけです。毎日計算する必要はありません。

カリー化関数を使用すると、計算を直前まで遅らせることができ、多くの場合、不必要な計算を回避でき、遅延評価を実現することができます。

さて、本題に入りましょう、

カーリングでは、いくつかのパラメータが事前に入力されます。

アンチカーリングとは、元々固定されていたパラメータまたはこのコンテキストをパラメータとして将来に延期することを意味します。

実際には、次のようなことを行うことになります:

obj.foo( arg1 ) //push が元々 Array.prototype のみにあるのと同じように、foo は元々 obj のみにある関数です。

このフォームに変換

foo( obj, arg1 ) // 最初の例と同じです。 [].push を Push( [] )

に変換します。

元々テレビのプラグに接続されていたソケットと同じように、取り外した後は実際に冷蔵庫を接続するために使用できます。

Ecma の配列と文字列の各プロトタイプ メソッドの後に、プッシュなどの段落があります。

注: Push 関数は意図的に汎用になっており、この値が Array オブジェクトである必要はありません。

したがって、concat 関数を適用できるかどうかに関係なく、他の種類のオブジェクトに転送できます。 .

なぜ Javascript はこのように設計されているのでしょうか? まず、動的言語における重要なダックタイピングの考え方を確認してみましょう。

ストーリーを語ってください:

昔、アヒルの鳴き声を聞くのが好きだった皇帝がいたので、大臣たちを呼んで千羽のアヒルからなる合唱団を結成させました。大臣は国中のアヒルをすべて捕まえましたが、結局一羽がいなくなってしまいました。ある日、ついにニワトリがやって来て、このニワトリも鳴くことができると言いました。 物語が進むにつれて、ニワトリがアヒルのコーラスの一部になっていることが明らかになります。 - 皇帝はただ鳴き声を聞きたいだけで、あなたがアヒルだろうがニワトリだろうが気にしません。

これはダック タイピングの概念です。JavaScript では、多くの関数はオブジェクトの種類の検出を行わず、オブジェクトが実行できることのみを考慮します。

Array コンストラクターと String コンストラクターのプロトタイプのメソッドは、ダック型になるように特別に設計されています。これらのメソッドは、this のデータ型の検証を実行しません。これが、引数が配列のふりをしてプッシュ メソッドを呼び出すことができる理由です。

v8 エンジンの Array.prototype.push のコードを確認します。


コードをコピーします コードは次のとおりです。 :

function ArrayPush() {
var n = TO_UINT32( this.length );
var m = %_ArgumentsLength();
for (var i = 0; i this[in] = %_Arguments(i); //属性コピー
this.length = n m; //長さの修正
return this.length>}
ご覧のとおり、ArrayPush メソッドは this の型に明示的な制限を課していないため、理論上は任意のオブジェクトを ArrayPush ビジターに渡すことができます。

解決しなければならない問題は 1 つだけ残っています。それは、一般的な方法でオブジェクトを配列オブジェクトのふりをする方法です。

実際の実装コードは実際には非常に単純です:

このコードは非常に短いですが、最初はまだ理解するのが少し難しいです。プッシュの例で何が起こるかを見てみましょう。


コードをコピーします。

コードは次のとおりです: var Push = Array.prototype.push.uncurrying();
push( obj, 'first' );




関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート