JavaScriptの関数プログラム

11879 ワード

関数式プログラミング(functional programming)または関数プログラム設計とも呼ばれ、汎関数プログラミングとも呼ばれ、命令式プログラミングよりも関数式プログラミングの方がプログラム実行の結果を強調し、いくつかの簡単な実行ユニットを利用して計算結果を漸進させ、階層ごとに複雑な演算を導き出すことを提唱しています.複雑な実行プロセスを設計するのではなく.
関数式プログラミングはここ数年ずっと炒められています.国内外の開発者はこのようなプログラミングのモデルを議論して提唱しているようです.多くの関数式言語の中で、Javascriptは間違いなく最も明るい目の一つであり、ますます多くの人がそれを学び、抱擁し始め、関数式プログラミングを使って実際の大規模な応用を開発しています.
webプラットフォームの唯一の標準的な共通語として、Javascriptはソフトウェアの歴史の上で最大の言語ブームを巻き起こしました.現在最大のオープンソース管理ツール(npm)を持つJavascriptもLispから数十年を維持する「最も流行している関数式プログラミング言語」の名前を受け取りました.Javascriptの世界では天然サポート関数式プログラミングで、関数式プログラミングの基本的な特徴は以下の通りです.
  • 一等関数
  • クローズド
  • 高次関数
  • 純度
  • 本文はJavascriptを例にして、皆さんと一緒に関数式プログラミングを理解して勉強します.
    一等関数(ファーストクラスFnctions)
    一等関数という用語は最初に20世紀の60年代にイギリスのコンピュータ科学者クリストファーストラチェがfunctions as first-class citizensの中で提出しました.関数は他の一等公民(Number/String...)と同じように、それらと同じ能力と役割を持つという意味です.
  • 関数は、変数
    const foo = () => {...}
  • として格納されています.
  • 関数は、データの1つの要素
    const arr = [1, 2, () => {...}]
  • として格納することができる.
  • 関数は、オブジェクトの属性値
    const obj = {name: 'xx', say: () => {}}
  • とすることができる.
  • 関数は、使用時に直接に
    1 + (() => { return 2; })()
  • を作成することができます.
  • 関数は、変数として他の関数
    bar (name, fun) { fun(name) }
    bar('xx', (name) => { console.log(name) })
  • に伝達されてもよい.
  • 関数は、他の関数によって
    foo() {
      return () => {...}
    }
  • に戻ることができる.
    関数プログラミングでは、関数は基本的なユニットとして機能の上にコードとデータのパッケージを作成し、アプリケーションの再利用と柔軟性を向上させます.一等関数をサポートする役割は明白であり,関数を用いて大部分の機能を達成することができる.
    クローズド(Cloure)
    30年を経て、ついにプログラミング言語の主要な特徴になりました.しかし、ある調査によると、Javascriptのクローズドに関する問題は23%前後を占め、かなりの数の開発者にとってはまだクローズドされておらず、神秘的である.クローズドの説明については、やはりKyle Simpsonのシリーズ本You Don’t Know JavaScriptの中の説明がより好きです.
    関数は定義されているときに現在の語法作用領域にアクセスでき、関数が作用領域から離れて実行されると、クローズドが形成される.
    簡単に言えば,クローズドは機能であり,作用領域内の外部バインディングを捕獲した.例を見てみます
    function student (people) {
      return (name) => { return people[name] }
    }
    var someone = student({xx: {age: 20}, jackson: {age: 21}})
    someone('xx') // {age: 20}
    student関数を実行した後、中の匿名関数はクローズドパケットを形成し、クローズドはペプシーオブジェクトにアクセスすることができます.クローズドはJavascriptのためにプライベートアクセスを提供しています.これは開発者にデータの抽象を確立させることによって非常に便利であり、関数コードをよりよく作成し、より強力なコードを構築することができます.
    一つの場面を考えてみると、本の配列が手元にあります.配列の中に本の情報が含まれています.今必要なのは本の名前を一つの配列に埋めて返すことです.私たちは普通こう書きます.
    const books = [{title: '    ', author: 'zz'}, {title: '         ', author: 'tt'}]
    
    books.map((item) => { return item.title })
    私たちはAray.prototype.map法を使用して、匿名関数が入ってきました.関数の中に本のタイトルtitleがあります.クローズドを利用してさらに抽象的にするなら、どう書きますか?
    function plucker (key) {
      return  (obj) => {
        return (obj && obj[key])
      }
    }
    
    books.map(plucker('title'))
    keyパラメータを受信して匿名関数に戻るplucker関数を定義したが、匿名関数はクローズドであり、keyパラメータを補足する.クローズドを利用した場合、コードの再使用性と柔軟性が向上します.私たちは十分にクローズドを認識し、合理的に実際の開発に活用すると、クローズドの威力とそれがもたらした便利さを身をもって実感することができます.
    高次関数(Higher Order Functions)
    数学とコンピュータ科学では、高次関数式は少なくとも次の条件を満たす関数である.
  • は、入力
  • として1つ以上の関数を受け取る.
  • は、関数
  • を出力します.
    上記のplucker関数は一例です.また、私たちがよく知っているAray.prototypeに関する方法があります.例えば.map、.sortなどは、一つの関数をパラメータとして受け入れる条件を満たす高次関数です.まず、一次関数の例を見て、関数を定義します.配列中の4文字の単語をフィルタリングします.
    const words = ['foo', 'bar', 'test', 'some']; 
    const filter = words => {
      let arr = [];
      for(let i = 0, { length } = words; i < length; i++) {
        const word = words[i];
        if(word.length !== 4) {
          arr.push(word);
        }
      }
      return arr;
    }
    
    filter(words); // ['foo', 'bar']
    もし今フィルタリングが必要なら、「b」で始まる単語?では、もう一つの関数を定義します.
    const startWith = words => {
      let arr = [];
      for(let i = 0, { length } = words; i < length; i++) {
        const word = words[i];
        if(word.indexOf('b') !== 0) {
          arr.push(word);
        }
      }
      return arr;
    }
    filter(words); // ['foo', 'test', 'some']
    上の2つの関数の比較から、実際には、主要コードの論理は似ています.まず、配列を通して条件判断を行い、最後にPushを配列の中に入れます.実際には、エルゴードとフィルタリングは抽象的にできます.他の類似関数の呼び出しに便利です.つまり、行列の中で条件によってフィルタリングするのが一般的な需要です.
    const reduce = (reducer, init, arr) => {
      let acc = init;
      for(let i = 0,{ length } = arr; i < length; i++) {
        acc = reducer(acc, arr[i]);
      }
      return acc;
    }
    reduce((acc, curr) => acc + curr, 0, [1, 2, 3]);    // 6
    Underscor e庫を使ったら、reduceとu.reduceの役割は同じで、実現するのは累計の機能です.reduceは3つのパラメータを受け取りました.ruducer関数、累積した初期値と1つの配列、各配列要素をreducerのパラメータとして入力し、戻り値は累積変数initに割り当てられ、遍歴が完了すると累積した機能が完了します.
    今は第一の需要にルデンスを適用すれば(4文字の単語をフィルタリングする):
    const func = (fn ,arr) => {
      return reduce((acc, curr) => fn(curr) ? acc.concat([curr]) : acc, [], arr)
    }
    console.log(func(word => word.length !== 4, words)); // ["foo", "bar"]
    共通コードを抽象化した後、filterの関数は非常に簡潔に実現され、異なる条件関数を導入するだけで、様々な条件に合ったデータを処理することができます.高次関数は関数の多形性を実現するために使用でき,高次関数の多重性と柔軟性は一次関数に対してより良い.
    純度(Purity)
    関数式プログラミングは、関数だけでなく、ソフトウェアの複雑さを最小限に抑える方法を考えるものです.いくつかの関数式プログラミング言語では、純度は強制的に実行され、副作用のある表現は使用できません.しかし、Javascriptでは、純度は管理領域によって実現されなければならず、非純粋関数を偶然に作成して使用しやすいです.
    純粋な関数は以下の3つの条件を満たす必要があります.
  • 関数の結果はパラメータのみで計算できます.
  • は、外部操作によって変更できるデータ
  • に依存してはいけない.
  • 外部状態を変えることができない
  • このような条件から見れば、Javascriptの世界において絶対的な純粋さを維持することは不可能であり、多くの関数式言語で使用される効率的で不変なデータ構造が欠けているからである.私たちは、Javascriptがfreeze()オブジェクトに行く能力を持っていることを知っていますが、オブジェクトのトップクラスの属性だけをドッキングすることができます.これは、ネストオブジェクトの下の属性がまだ変更されていることを意味します.
    var obj = Object.freeze({
        foo: 'hello',
        bar: {
            text: 'world'
        }
    })
    
    obj.foo = 'goodbye';
    console.log(obj.foo); // hello
    
    obj.bar.text = 'goobye';
    console.log(obj.bar.text); // goodbye
    ES 6に追加されたconstキーは、constを使用して異なる値に再割り当てできないが、1つのconstオブジェクトの属性はまだ可変であると定義することができる.
    const obj = 'hello';
    obj = 'goodbye';    // Uncaught TypeError: Assignment to constant variable.
    
    const obj = {
        foo: 'hello',
        bar: 'world'
    }
    
    obj.foo = 'goodbye';
    console.log(obj);     // {foo: 'goodbye', bar: 'world'}
    Javascrptで総合不変性を実現するにはまだ長い道のりがあります.言い換えれば、絶対的な純粋さを保証することはできませんが、純粋な部分を抜き出すことができます.変化の影響を最小限にして、コードがより一般的になり、テストしやすくなります.
    まとめ:
  • 関数式プログラミングは、他のデータタイプと同じ機能を持つ1等関数をサポートします.
  • 関数式プログラミングでは、クローズドパケットを使用してデータのパッケージ
  • を実行します.
  • は、高次関数を使用してコードの抽象化を確立し、コードをより柔軟に汎用化する.
  • は、コードの測定可能性と汎用性を維持するために、できるだけ純関数から抽出する.
    ps:もし間違ったところがあったら、ご指摘を歓迎します.できるだけ早く修正します.ありがとうございます.
    参考文献:
  • ウィキペディア
  • Why Learn Funtional Programeming in JavaScript?エリックElliott
  • Higher Order Functions--Elliot
  • Javascript関数式プログラミング--マイケルFogs