機能的なプログラミングベースのJavaScriptアプリはどのようにレイアウトされていますか?
質問
私は一緒に仕事をしてきました node.js しばらくの間、チャットアプリを使用しています(非常に独創的ですが、それは良い学習プロジェクトになると思いました)。 underscore.js 興味深いように見える多くの機能的なプログラミングの概念を提供するので、JavaScriptの機能プログラムがどのようにセットアップされるかを理解したいと思います。
機能的なプログラミング(間違っている可能性があるかもしれません)を理解することから、全体のアイデアは副作用を回避することです。これは基本的に、関数の外側の別の変数を更新する関数を持っています。
var external;
function foo() {
external = 'bar';
}
foo();
副作用を生み出すでしょうか?したがって、一般的なルールとして、グローバル範囲の変数を乱すことを避けたいと思うでしょう。
わかりました、それで、あなたがオブジェクトを扱っているとき、それはどのように機能しますか?たとえば、多くの場合、私はコンストラクターとオブジェクトを初期化するINITメソッドを持っています。
var Foo = function(initVars) {
this.init(initVars);
}
Foo.prototype.init = function(initVars) {
this.bar1 = initVars['bar1'];
this.bar2 = initVars['bar2'];
//....
}
var myFoo = new Foo({'bar1': '1', 'bar2': '2'});
したがって、私のinit方法は意図的に副作用を引き起こすことですが、同じ種類の状況を処理する機能的な方法は何ですか?
解決
あなたはこの質問を読むべきです:
以下を含む多くの有用なリンクがあります。
- 機能的なプログラミング技術を使用して、エレガントなJavaScriptを書きます
- リトルジャバスクリプター
- 高次JavaScript
- Eloquent JavaScript、第6章:機能プログラミング
今、私の意見のために。多くの人々 JavaScriptを誤解しています, 、おそらくその構文は他のほとんどのプログラミング言語のように見えるためです(LISP/Haskell/OCAMLは完全に異なって見えます)。 JavaScriptはです いいえ オブジェクト指向、それは実際にはaです プロトタイプベースの言語. 。クラスや古典的な継承がないため、JavaやC ++と実際に比較されるべきではありません。
JavaScriptは、LISPと比較して優れています。閉鎖と一流の機能があります。それらを使用すると、他の機能的なプログラミング手法を作成できます。 部分アプリケーション (カリー)。
例を見てみましょう(使用してください sys.puts
node.jsから):
var external;
function foo() {
external = Math.random() * 1000;
}
foo();
sys.puts(external);
グローバルな副作用を取り除くために、閉鎖に包むことができます。
(function() {
var external;
function foo() {
external = Math.random() * 1000;
}
foo();
sys.puts(external);
})();
実際に何もできないことに注意してください external
また foo
スコープの外。彼らは完全に自分の閉鎖に包まれており、手に負えない。
さて、それを取り除くために external
副作用:
(function() {
function foo() {
return Math.random() * 1000;
}
sys.puts(foo());
})();
最終的に、その例は純粋に機能していません。 できません なれ。乱数を使用すると、グローバルな状態(種子を取得するため)から読み取り、コンソールへの印刷は副作用です。
また、機能的なプログラミングとオブジェクトを混合することは完全に問題ないことを指摘したいと思います。これについては、次のようにしてください。
var Square = function(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
};
function getArea(square) {
return square.w * square.h;
}
function sum(values) {
var total = 0;
values.forEach(function(value) {
total += value;
});
return total;
}
sys.puts(sum([new Square(0, 0, 10, 10), new Square(5, 2, 30, 50), new Square(100, 40, 20, 19)].map(function(square) {
return getArea(square);
})));
ご覧のとおり、機能的な言語でオブジェクトを使用することは問題ありません。一部のLISPには、オブジェクトと考えることができるプロパティリストと呼ばれるものさえあります。
機能スタイルでオブジェクトを使用する本当のトリックは、副作用に頼らず、代わりにそれらを不変として扱うことを確認することです。簡単な方法は、プロパティを変更したいときはいつでも、 新着 代わりに、新しい詳細を備えたオブジェクトとそれを渡します(これは、ClojureとHaskellでよく使用されるアプローチです)。
機能的な側面はJavaScriptで非常に役立つ可能性があると強く信じていますが、最終的には、コードをより読みやすくするものとあなたのために機能するものを使用する必要があります。
他のヒント
機能的なプログラミングとオブジェクト指向プログラミングは、互いにやや反対であることを理解する必要があります。両方になることは不可能です 純粋に機能的です そして純粋にオブジェクト指向。
機能プログラミング すべてのステートレス計算に関するものです。 オブジェクト指向プログラミング 州の移行に関するものです。 (パラフォーシング これ. 。うまくいけば、それほどひどくない)
JavaScriptは、機能するよりもオブジェクト指向です。つまり、純粋に機能的なスタイルでプログラムしたい場合は、言語の大部分を放棄する必要があります。具体的には、すべてのオブジェクトオリエントパーツ。
あなたがそれについてより実用的になることをいとわないなら、あなたが使用できる純粋に機能的な世界からいくつかのインスピレーションがあります。
私は次のルールを遵守しようとします。
計算を実行する関数は状態を変更してはなりません。状態を変更する関数は、計算を実行してはなりません。また、状態を変更する関数は、できるだけ小さな状態を変更する必要があります。目標は、1つだけを行うだけの小さな機能をたくさん持っていることです。その後、何か大きなことをする必要がある場合は、必要なことをするためにたくさんの小さな機能を構成します。
これらのルールに従うことから得られる多くの利点があります。
再利用の容易さ。長くて複雑な関数があれば、それもより専門的であるため、再利用できる可能性は低くなります。逆の意味は、より短い機能がより一般的であるため、再利用しやすい傾向があることです。
コードの信頼性。コードが複雑ではない場合、コードの正しさについて推論する方が簡単です。
関数が1つしかない場合、機能をテストする方が簡単です。そうすれば、テストする特別なケースが少なくなります。
アップデート:
コメントからの提案を組み込んだ。
更新2:
いくつかの便利なリンクを追加しました。
おもう、 http://documentcloud.github.com/underscore/ 必要なものに適しているはずです - 機能プログラミングのための最も重要な高次関数を提供し、サーバー側には必要のないDOM操作のクライアント側機能がありません。経験はありませんが。
サイドノートとして:機能プログラミングの主な特徴は 参照透明性 関数 - 関数の結果は、そのパラメーターにのみ依存します - 関数は他のオブジェクトの変更に依存せず、結果値以外の変更は導入されません。これにより、プログラムの正確性について簡単に推論することができ、予測可能なマルチスレッド(関連する場合)の実装に非常に価値があります。 JavaScriptはFPのBET言語ではありませんが、不変のデータ構造は非常に高価なパフォーマンスで使用することを期待しています。
だから、指摘すべき2つのこと、
最初の例では、変数はグローバルエリアに漏れず、その方法です。それらを宣言せずに変数を使用しないようにしてください。IETEST= 'DATA'はデータをグローバルエリアに漏らします。
2番目の例も正しいです。BAR1とBAR2はFOOオブジェクトでのみ宣言されます。
心に留めておくべきことは、プロトタイピングを使用しないようにしてください。これは、作成するすべてのオブジェクトに適用されます。これは、オブジェクトの複雑さに応じて非常にメモリ集約的である可能性があります。
アプリ開発フレームワークをお探しの場合は、 extjs. 。個人的には、あなたが開発しようとしているモデルに完全に適合すると思います。ライセンスモデルがどのように機能するかを覚えておいてください。