ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptを使った関数型プログラミングの詳しい入門(1)(写真)

JavaScriptを使った関数型プログラミングの詳しい入門(1)(写真)

黄舟
黄舟オリジナル
2017-03-11 15:07:141472ブラウズ

この記事は、関数型プログラミング シリーズの最初の記事です。ここでは、プログラミング パラダイムを簡単に紹介し、次に Javascript を使用した関数型プログラミングの概念に直接進みます。なぜなら、JavsScript は最もよく知られている関数型プログラミング言語の 1 つであるためです。読者は、「参考文献」セクションを通じてこの魅力的な概念についてさらに詳しく学ぶことをお勧めします。

プログラミングパラダイム

プログラミングパラダイムは、問題について考え、問題のビジョンを実現するためのツールで構成されるフレームワークです。現代言語の多くはポリパラダイム (またはマルチパラダイム) です。オブジェクト指向、メタプログラミング、関数型、手続き型など、さまざまなプログラミング パラダイムをサポートしています。

使用 JavaScript 进行函数式编程 (一)

関数型プログラミングのパラダイム

関数型プログラミングは水素で動く自動車のようなもので、先進的で未来的ですが、まだ広く採用されていません。命令型プログラミングとは対照的に、実行時にグローバル状態を更新する一連のステートメントで構成されます。関数型プログラミングでは、計算が式の評価に変わります。これらの式はすべて純粋な数学関数で構成されており、第一級であり (通常の値として使用および処理できます)、副作用はありません。

使用 JavaScript 进行函数式编程 (一)

関数型プログラミングの値 次の値:

関数は最優先事項です

関数はプログラミング言語の他のクラス オブジェクトと同じように扱う必要があります。つまり、関数を変数に格納したり、関数を動的に作成したり、関数を返したり、関数を他の関数に渡したりすることができます。例を見てみましょう...

使用 JavaScript 进行函数式编程 (一)

文字列は変数として保存でき、関数も同様に保存できます。例:

var sayHello = function() { return “Hello” };

文字列はオブジェクトフィールドとして保存でき、関数、例:

var person = {message: “Hello”, sayHello: function() { return “Hello” }};

文字 再度必要になったときに文字列を作成でき、関数も作成できます。例:

“Hello ” + (function() { return “World” })(); //=> Hello World

文字列を入力パラメータとして関数に渡すことができ、関数は次のようにすることができます。

    function hellloWorld(hello, world) { return hello + world() }

文字列は関数の戻り値として使用でき、関数も同様に使用できます。 例:

return “Hello”;
return function() { return “Hello”};

高次の場合

使用 JavaScript 进行函数式编程 (一)

関数が他の関数を入力パラメータまたは戻り値として受け取る場合値を表す関数は高階関数と呼ばれます。高階関数の例を見てきました。次に、より複雑な状況を見てみましょう。

例 1:

[1, 2, 3].forEach(alert);
// alert 弹窗显示“1" 
// alert 弹窗显示 "2" 
// alert 弹窗显示 "3”

例 2:

function splat(fun) {
   return function(array) {
        return fun.apply(null, array);
   };
}
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements([1, 2]);
//=> 3

Favorite純粋関数

使用 JavaScript 进行函数式编程 (一)

純粋関数には他の副作用はありません。いわゆる副作用を指します。関数 関数の外部状態の変更。例:

  • 変数を変更する

  • データ構造を変更する

  • 外部変数にフィールドを設定する

  • 例外をスローするか、エラーメッセージをポップアップする

最も単純な例は次のとおりです。数学関数。 Math.sqrt(4) 関数は常に 2 を返します。ステータスや設定パラメータなどの他の冷却情報は使用されません。数学関数が副作用を引き起こすことはありません。

状態の変更を避ける

使用 JavaScript 进行函数式编程 (一)

関数型プログラミングは純粋関数をサポートしており、そのような関数はデータを変更できないため、主に不変データを作成するために使用されます。この方法では、既存のデータ構造を変更する必要はなく、新しいデータ構造を効率的に作成できます。

一部のローカル データを変更することによって純粋関数が不変の戻り値を生成するかどうか知りたい場合がありますが、それは許可されていますか? ?答えは「はい」です。
JavaScript ではデフォルトで不変のデータ型はほとんどありません。文字列は変更できないデータ型の例です:

   var s = "HelloWorld";
    s.toUpperCase();
    //=> "HELLOWORLD"
    s;
    //=> "HelloWorld"

不変状態の利点

• 混乱を避け、プログラムの精度を向上します: 複雑なシステムでは、理解できないバグのほとんどはプログラムを通過する状態に起因します 外部クライアント コードが原因です修正。
• 「高速かつ簡潔な」マルチスレッド プログラミングを確立します。複数のスレッドが同じ共有値を変更できる場合は、その値を同期的に取得する必要があります。これは専門家にとって、退屈でエラーが発生しやすいプログラミングの課題です。
ソフトウェア トランザクション メモリとアクター モデルは、スレッドセーフな方法で変更を直接処理します。

ループ呼び出しの代わりに再帰を使用します

使用 JavaScript 进行函数式编程 (一)

递归是最有名的函数式编程技术。如果您还不知道它的话,那么可以理解为递归函数就是一个可以调用自己的函数。

替代反复循环的最经典方式就是使用递归,即每次完成函数体操作之后,再继续执行集合里的下一项,直到满足结束条件。递归还天生符合某些算法实现,比如遍历树形结构(每个树枝都是一颗小树)。

在任何语言里,递归都是一项重要的函数式编程方式。很多函数语言甚至要求的更加严格:只支持递归遍历,而不支持显式的循环遍历。这需要语言必须保证消除了尾端调用,这是 JavasSrip 不支持的。

惰性求值优于激进计算

使用 JavaScript 进行函数式编程 (一)

数学定义了很多无穷集合,比如自然数(所有的正整数)。他们都是符号表示。任意特定有限的子集都在需要时求值。我们将其称之为惰性求值(也叫做非严格求值,或者按需调用,延迟执行)。及早求值会强迫我们表示出所有无穷数据,而这显然是不可能的。

很多语言都默认是惰性的,有些也提供了惰性数据结构以表达无穷集合,并在需要时对自己进行精确计算。

很明显一行代码 result = compute() 所表达的是将 compute() 的返回结果赋值给 result。但是 result 的值究竟是多少只有其被用到的时候才有意义。

可见策略的选择会在很大程度上提高性能,特别是当用在链式处理或者数组处理的时候。这些都是函数式程序员所喜爱的编程技术。

这就开创可很多可能性,包括并发执行,并行技术以及合成。

但是,有一个问题,JavaScrip 并不对自身进行惰性求值。话虽如此,Javascript 里的函数库可以有效地模拟惰性求值。

闭包的全部好处

所有的函数式语言都有闭包,然而这个语言特性经常被讨论得很神秘。闭包是一个函数,这个函数有着对内部引用的所有变量的隐式绑定。换句话说,该函数对它引用的变量封闭了一个上下文。JavaScript 中的闭包是能够访问父级作用域的函数,即使父级函数已经调用完毕。

   function multiplier(factor) {
      return function(number) {
          return number * factor;
      };
   }
  var twiceOf = multiplier(2);
    console.log(twiceOf(6));
//=> 12

声明式优于命令式编程

函数式编程是声明式的,就像数学运算,属性和关系是定义好的。运行时知道怎么计算最终结果。阶乘函数的定义提供了一个例子:

factorial(n)       = 1 if n = 1

                            n * factorial(n-1) if n > 1

该定义将 factorial(n) 的值关联到 factorial(n-1),是递归定义。特殊情况下的 factorial(1) 终止了递归。

var imperativeFactorial = function(n) {
    if(n == 1) {
        return 1
    } else {
        product = 1;
        for(i = 1; i <= n; i++) {
              product *= i;
        }
        return product;
     }
}
var declarativeFactorial = function(n) {
       if(n == 1) {
             return 1
       } else {
             return n * factorial(n - 1);
      }
  }

从它实现阶乘计算来看,声明式的阶乘可能看起来像“命令式”的,但它的结构更像声明式的。

命令式阶乘使用可变值、循环计数器和结果来累加计算后的结果。这个方法显式地实现了特定的算法。不像声明式版本,这种方法有许多可变步骤,导致它更难理解,也更难避免 bug 。

使用 JavaScript 进行函数式编程 (一)

函数式JavaScript库

有很多函数式库:underscore.js, lodash,Fantasy Land, Functional.js, Bilby.js, fn.js, Wu.js, Lazy.js, Bacon.js, sloth.js, stream.js, Sugar, Folktale, RxJs 等等。

函数式程序员工具包

map(), filter(), 和 reduce()函数 构成了函数式程序员工具包的核心。 纯高阶函数成了函数式方法的主力。事实上,它们是纯函数和高阶函数应该仿效的典型。它们用一个函数作为输入,返回没有副作用的输出。

以上がJavaScriptを使った関数型プログラミングの詳しい入門(1)(写真)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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