javascript関数式プログラミング

11772 ワード

関数式プログラミングは先端でもう話題になりました.近年多くのアプリケーションコード庫で関数式プログラミング思想が大量に使われています.ここではJavaScriptの関数式プログラミングについて簡単に分かります.
関数プログラミングとは何ですか?
関数プログラミングは、主に関数を用いて演算プロセスをカプセル化し、各種の関数を組み合わせて結果を計算するプログラムの範式である.関数プログラミングは、開発者がより短い時間でより少ないエラーを持つコードを作成できることを意味します.
関数プログラミングの簡単な例
文字列を各単語の最初の文字に変換する場合、このようにして実行できます.
var string = 'i do like yanggb';
var result = string
    .split(' ')
    .map(v => v.slice(0, 1).toUpperCase() + v.slice(1))
    .join(' ');
この例では、所望の結果を得るために、まずスプリットメソッドを呼び出して文字列を配列に変換してから、map()メソッドを呼び出して各要素の頭文字を大文字に変換し、最後にジョイン()メソッドを呼び出して配列を文字列に変換します.ここでのプロセス全体はjoin(map(str))であり、関数プログラミングの核心思想を体現しています.関数によってデータを変換します.
関数プログラミングの二つの基本的な特徴
上記の例を通して、関数式プログラミングには二つの基本的な特徴があります.
1.関数でデータを変換します.
2.直列の複数の関数で最終結果を求めます.
命令式プログラミング、宣言式プログラミングとの比較
ここでは、関数式プログラミングとコマンド式プログラミングと宣言式プログラミングの違いを簡単に比較します.
命令式プログラミングとは?
命令式プログラミングとは、一つ又一つの命令を作成することによって、コンピュータにいくつかの動作を実行させます.この中には多くの煩雑な詳細が含まれます.命令式コードでは、文を頻繁に使用して、for、if、switch、throwなどの行為を行います.
//      
var vegetable = ['  ', '  ', '   ', '  ', '  '];
var food = [];
for (var i = 0; i < vegetable.length; i++) {
    food.push(vegetable[i]);
}
宣言式プログラミングとは?
ステートプログラミングとは、表現を書くことによって、私たちが何をしたいのかを声明することであり、一歩一歩の命令ではなく、コマンドプログラミングの簡単なパッケージに相当する.これらの表式は、通常、特定の関数で呼び出される複合、いくつかの値、およびオペレータであり、所望の結果値を計算するために使用される.
//      
var food = vegetable.map(c => c);
関数プログラミングとコマンドプログラミング、ステートメントプログラミングの違い
上記の例からは、ステートメント式の書き方は式であり、カウンタの反復をどのように行うかに関心がなくても、帰ってくる配列はどのように収集されていますか?関数プログラミングの明らかな利点は、このような宣言式のコードであり、副作用のない純粋な関数については、関数の内部がどのように実現されるかを全く考慮しないことができ、開発者は業務コードの作成に専念できます.
関数プログラミングの特性
関数プログラミングにはいくつかの一般的な特性があります.
副作用がない
副作用のない特性とは、関数を呼び出したときに外部の状態を変更しないこと、すなわち関数がn回呼んだ後も同じ結果を返すことです.
var a = 1;

function f1() { //          
    a++; //      ,         a
    return a;
}

function f2(a) { //         
    return a + 1;  //
}
透明な参照
透明参照の特性とは、関数が与えられた変数と自分の内部で作成した変数だけを使用して、他の変数(外部変数)には使用されないことを意味します.この特性は副作用のない特性と呼応する.
var a = 1, b = 2;

function f1() { //                   
    return a + b;
}

function f2(a, b) { //                  
    return a + b;
}
変数
変数の特性とは、作成が完了すると、変更されなくなり、任意の変更で新しい変数が生成されます.不可変変数を使う最大の利点はスレッドセキュリティであり、複数のスレッドは同時に同じ可変変数にアクセスでき、状態の不一致を心配することなく、並列が容易に実現できるようになる.
しかし、JavaScript原生は可変変数に対応していないため、第三者ライブラリ(例えばImmutable.jsやMoriなど)で実現する必要があります.
var obj = Immutable({a: 1});
var obj2 = obj.set('a', 2);
console.log(obj); // Immutable({a: 1})
console.log(obj2); // Immutable({a: 2})
関数は一等公民です.
関数はJavaScriptの1等公民とよく言われています.関数は他のデータタイプと同じように平等な地位にあるということです.関数は他の変数に値を割り当てたり、パラメータとして別の関数に入力したり、他の関数の戻り値として返したりすることができます.JavaScriptのクローズド、高次関数、関数コリックと関数の組み合わせはこの特性をめぐる応用である.
一般的な関数式プログラミングモデル
一般的な関数式プログラミングモデルは、クローズド、高次関数、関数コリック、関数の組み合わせがあります.
クローズド(Cloure)
関数が自由変数を参照すると、この関数は閉じられています.自由変数とは、その関数のスコープに属さない変数(すべての大域変数は自由変数)のことです.厳密な意味では、グローバル変数の関数はすべてクローズドです.しかし、このようなクローズドはあまり効果がないので、通常の意味でのクローズドとは関数内部の関数です.
閉ループの形成条件は、2つに分割されてもよい.
1.内、外の二重関数があります.
2.内層関数の外層関数の局所変数を参照しました.
クローズドの用途は、キャッシュまたは計算の中間の2つを行うために、いくつかの作用領域の限界を定義する恒久化変数である.
//          
//              
const cache = (function() {
    const store = {};
    return {
        get(key) {
            return store[key];
        },
        set(key, val) {
            store[key] = val;
        }
    }
}());
console.log(cache); // {get: ƒ, set: ƒ}
cache.set('a', 1);
cache.get('a'); // 1
上記のコードは簡単なキャッシュツールの実現例であり、匿名関数を用いて、storeオブジェクトが回収されずに参照されてもよいように、クローズドパケットを作成した.
注意すべきなのは、恒久化された変数は正常には解放されません.メモリ空間を占有し続けるため、メモリの無駄をもたらしやすく、いくつかの追加の手動のクリーンアップメカニズムが必要です.これはクローズドの最大の弊害です.
高次関数(High Order Function)
関数プログラミングは、一般的な関数機能のセットを多重化してデータを処理する傾向があり、高次関数を使用して実現される.したがって、高次関数は、関数をパラメータとしたり、関数を返し値としたり、関数をパラメータとしたり、関数を返し値としたりする関数を指します.
高次関数が使用するシーン:
1.抽象的または隔離的な行為、作用、非同期的な制御プロセスは、プロミセスとmondadsなどのコールバック関数として機能します.
2.さまざまなデータタイプに共通する機能を作成します.
3.関数パラメータ(偏関数応用)に部分的に適用したり、多重化や関数再結合のためにコーリ化の関数を作成したりします.
4.関数のリストを受け取り、このリストの関数によって結合されたいくつかの複合関数を返します.
JavaScriptは、Aray.prototype.map、Aray.prototype.filterとAray.prototype.reduceのような高次関数を原生がサポートしています.これらの高次関数を使うと,コードが明瞭で簡潔になる.
関数コリック化(Function Currying)
関数のカリー化は実は高次関数の特殊な応用であり、また部分的な値求めとも言われています.カリー化関数は、いくつかのパラメータを受信し、すぐに値を求めることなく、新しい関数を返し続けます.そして、入ってきたパラメータをクローズド形式で保存します.本当に値を求められた時に、一度にすべてのパラメータを使って値を求めます.
一般関数:
function add(x, y){
    return x + y;
}
関数コリック化:
var add = function(x) {
    return function(y) {
        return x + y;
    };
};
var increment = add(1);

increment(2); // 3
ここでは、一つのパラメータを受信し、新しい関数を返すadd()関数を定義します.add()関数を呼び出した後、返された関数は、add()関数で渡されるパラメータをクローズド形式で保存します.
コリック関数:
function curryIt(fn) {
    //   fn       
    var n = fn.length;
    var args = [];
    return function(arg) {
        args.push(arg);
        if (args.length < n) {
            return arguments.callee; //          
        } else {
            return fn.apply(this, args);
        }
    };
}

function add(a, b, c) {
    return [a, b, c];
}

var c = curryIt(add);
var c1 = c(1);
var c2 = c1(2);
var c3 = c2(3);

console.log(c3); // [1, 2, 3]
このことから,関数コリック化はプリロード関数の手法であり,特に少ない関数を伝達することによって,これらのパラメータを覚えた新しい関数を得ることができる.ある意味では、これはパラメータをキャッシュする方法であり、非常に効率的に関数を作成する方法である.
関数グループ(Function Componesition)
上述したように、関数式プログラミングの特徴は直列関数によって求められます.しかし,直列関数の数が増加すると,コードの可読性は継続的に低下する.関数の組み合わせはこの問題を解決するためのスキームです.compose()関数があると仮定して、パラメータとして複数の関数を受信し、新しい関数を返します.このように、私たちはこの新しい関数にパラメータを渡すと、これらのパラメータはその関数間で伝達され、最終的には所望の結果を返します.
//        
var compose = function(f, g) {
    return function(x) {
       return f(g(x));
    };
};

//   
var compose = (f, g) => (x => f(g(x)));
var add1 = x => x + 1;
var mul5 = x => x * 5;

//   
compose(mul5, add1)(2); // 15
 
どうせできないなら、何でもいいです.