Rumah >hujung hadapan web >tutorial js >Kemahiran bahasa pengaturcaraan fungsi Javascript_javascript
Bahasa pengaturcaraan berfungsi
Bahasa pengaturcaraan fungsional adalah bahasa yang memudahkan penggunaan paradigma pengaturcaraan berfungsi. Ringkasnya, jika ia mempunyai ciri-ciri yang diperlukan untuk pengaturcaraan berfungsi, ia boleh dipanggil bahasa berfungsi. Dalam kebanyakan kes, gaya pengaturcaraan sebenarnya menentukan sama ada program berfungsi.
Apakah yang menjadikan bahasa berfungsi?
Pengaturcaraan fungsian tidak boleh dilaksanakan dalam bahasa C. Pengaturcaraan fungsian tidak boleh dilaksanakan dalam Java (tidak termasuk pengaturcaraan yang menganggarkan pengaturcaraan berfungsi melalui banyak penyelesaian). Bahasa-bahasa ini tidak mengandungi binaan untuk menyokong pengaturcaraan berfungsi. Ia adalah bahasa berorientasikan objek semata-mata, tidak berfungsi sepenuhnya.
Pada masa yang sama, pengaturcaraan berorientasikan objek tidak boleh digunakan dalam bahasa berfungsi tulen, seperti Skim, Haskell dan Lisp.
Walau bagaimanapun, sesetengah bahasa menyokong kedua-dua mod. Python ialah contoh yang terkenal, tetapi terdapat yang lain: Ruby, Julia, dan yang paling menarik, Javascript. Bagaimanakah bahasa ini menyokong kedua-dua corak reka bentuk yang berbeza ini? Ia mengandungi ciri-ciri yang diperlukan oleh kedua-dua paradigma pengaturcaraan. Walau bagaimanapun, untuk Javascript, ciri-ciri fungsi nampaknya tersembunyi.
Tetapi sebenarnya, bahasa berfungsi memerlukan lebih sedikit daripada yang di atas. Apakah ciri-ciri bahasa berfungsi?
特点 | 命令式 | 函数式 |
---|---|---|
编程风格 | 一步一步地执行,并且要管理状态的变化 | 描述问题和和所需的数据变化以解决问题 |
状态变化 | 很重要 | 不存在 |
执行顺序 | 很重要 | 不太重要 |
主要的控制流 | 循环、条件、函数调用 | 函数调用和递归 |
主要的操作单元 | 结构体和类对象 | 函数作为一等公民的对象和数据集 |
Sintaks bahasa berfungsi mesti mengambil kira corak reka bentuk tertentu, seperti sistem inferens jenis dan fungsi tanpa nama. Secara umum, bahasa mesti melaksanakan kalkulus lambda. Dan strategi penilaian jurubahasa mestilah tidak ketat, panggilan atas permintaan (juga dipanggil pelaksanaan malas), yang membolehkan struktur data tidak berubah dan penilaian malas yang tidak ketat.
译注:这一段用了一些函数式编程的专业词汇。lambda演算是一套函数推演的形式化系统(听起来很晕), 它的先决条件是内部函数和匿名函数。非严格求值和惰性求值差不多一个意思,就是并非严格地按照运算规则把所有元素先计算一遍, 而是根据最终的需求只计算有用的那一部分,比如我们要取有一百个元素的数组的前三项, 那惰性求值实际只会计算出一个具有三个元素是数组,而不会先去计算那个一百个元素的数组。
Kelebihan
Pengaturcaraan fungsional akan menjadi inspirasi besar apabila anda akhirnya menguasainya. Pengalaman seperti ini akan membawa kerjaya masa depan anda sebagai pengaturcara ke tahap yang lebih tinggi, tidak kira sama ada anda benar-benar akan menjadi pengaturcara berfungsi sepenuh masa.
Tetapi kami tidak bercakap tentang cara belajar bermeditasi sekarang; kami bercakap tentang cara mempelajari alat yang sangat berguna yang akan menjadikan anda seorang pengaturcara yang lebih baik.
Secara keseluruhan, apakah kelebihan praktikal sebenar menggunakan pengaturcaraan berfungsi?
Kod pembersih
Pengaturcaraan berfungsi lebih bersih, ringkas dan lebih kecil. Ia memudahkan penyahpepijatan, ujian dan penyelenggaraan.
Sebagai contoh, kita memerlukan fungsi yang menukar tatasusunan dua dimensi kepada tatasusunan satu dimensi. Jika kita hanya menggunakan teknik imperatif, kita akan menulisnya seperti ini:
function merge2dArrayIntoOne(arrays) { var count = arrays.length; var merged = new Array(count); var c = 0; for (var i = 0; i < count; ++i) { for (var j = 0, jlen = arrays[i].length; j < jlen; ++j) { merged[c++] = arrays[i][j]; } } return merged }
Kini menggunakan teknik berfungsi, ia boleh ditulis seperti ini:
merge2dArrayIntoOne2 = (arrays) -> arrays.reduce (memo, item) -> memo.concat item , []
var merge2dArrayIntoOne2 = function(arrays) { return arrays.reduce( function(p,n){ return p.concat(n); }, []); };
译注:原著中代码有误,调用reduce函数时少了第二个参数空数组,这里已经补上。
Kedua-dua fungsi mengambil input yang sama dan mengembalikan output yang sama, tetapi contoh berfungsi adalah lebih bersih.
Modular
Pengaturcaraan fungsional memaksa anda memecahkan masalah besar kepada kes yang lebih kecil yang menyelesaikan masalah yang sama, yang bermaksud kod akan menjadi lebih modular. Program modular mempunyai penerangan yang lebih jelas, lebih mudah untuk nyahpepijat dan lebih mudah untuk diselenggara. Pengujian juga akan menjadi lebih mudah kerana setiap kod modul boleh disemak secara bebas untuk memastikan ketepatannya.
Kebolehgunaan semula
Disebabkan sifat modularnya, pengaturcaraan berfungsi mempunyai banyak fungsi tambahan biasa. Anda akan mendapati bahawa banyak fungsi di sini boleh digunakan semula dalam beberapa aplikasi yang berbeza.
Dalam bab berikut, banyak fungsi yang paling biasa akan dibincangkan. Walau bagaimanapun, sebagai pengaturcara berfungsi, anda pasti akan menulis perpustakaan fungsi anda sendiri yang akan digunakan berulang kali. Contohnya, fungsi yang digunakan untuk mencari fail konfigurasi antara baris juga boleh digunakan untuk mencari jadual Hash jika ia direka bentuk dengan baik.
Kurangkan gandingan
Gandingan ialah sejumlah besar kebergantungan antara modul dalam program. Memandangkan pengaturcaraan berfungsi mengikuti penulisan fungsi tulen peringkat pertama, tingkat tinggi, yang tidak mempunyai kesan sampingan pada pembolehubah global dan bebas sepenuhnya antara satu sama lain, gandingan dikurangkan dengan banyaknya. Sudah tentu, fungsi tidak dapat dielakkan bergantung antara satu sama lain, tetapi menukar satu fungsi tidak akan menjejaskan yang lain, selagi pemetaan satu sama satu input dan output kekal betul.
Ketepatan Matematik
Poin terakhir lebih kepada teori. Kerana ia berakar umbi dalam kalkulus lambda, pengaturcaraan berfungsi boleh dibuktikan betul secara matematik. Ini merupakan kelebihan besar bagi sesetengah penyelidik yang memerlukan program untuk membuktikan kadar pertumbuhan, kerumitan masa dan ketepatan matematik.
Mari kita lihat Jujukan Fibonacci. Walaupun ia jarang digunakan di luar masalah pembuktian konsep, ia merupakan cara yang bagus untuk menerangkan konsep tersebut. Cara standard untuk menilai jujukan Fibonacci adalah dengan mencipta fungsi rekursif, seperti ini:
fibonnaci(n) = fibonnaci(n-2) + fibonnaci(n–1)
Anda juga perlu menambah situasi umum:
return 1 when n < 2
Ini membolehkan rekursi ditamatkan dan membenarkan setiap langkah dalam timbunan panggilan rekursif terkumpul dari sini.
Langkah terperinci disenaraikan di bawah
var fibonacci = function(n) { if (n < 2) { return 1; }else { return fibonacci(n - 2) + fibonacci(n - 1); } } console.log( fibonacci(8) ); // Output: 34
Walau bagaimanapun, dengan bantuan perpustakaan fungsi pelaksanaan yang malas, adalah mungkin untuk menjana urutan tak terhingga dengan mentakrifkan ahli keseluruhan jujukan melalui persamaan matematik. Hanya ahli yang kita perlukan akhirnya dikira pada akhirnya.
var fibonacci2 = Lazy.generate(function() { var x = 1, y = 1; return function() { var prev = x; x = y; y += prev; return prev; }; }()); console.log(fibonacci2.length()); // Output: undefined console.log(fibonacci2.take(12).toArray()); // Output: [1, 1, 2, 3, 5,8, 13, 21, 34, 55, 89, 144] var fibonacci3 = Lazy.generate(function() { var x = 1, y = 1; return function() { var prev = x; x = y; y += prev; return prev; }; }()); console.log(fibonacci3.take(9).reverse().first(1).toArray()); //Output: [34]
第二个例子明显更有数学的味道。它依赖Lazy.js函数库。还有一些其它这样的库,比如Sloth.js、wu.js, 这些将在第三章里面讲到。
我插几句:后面这个懒执行的例子放这似乎仅仅是来秀一下函数式编程在数学正确性上的表现。 更让人奇怪的是作者还要把具有相同内部函数的懒加载写两遍,完全没意义啊…… 我觉得各位看官知道这是个懒执就行了,不必深究。
非函数式世界中的函数式编程
函数式和非函数式编程能混合在一起吗?尽管这是第七章的主题,但是在我们进一步学习之前, 还是要弄明白一些东西。
这本书并没要想要教你如何严格地用纯函数编程来实现整个应用。这样的应用在学术界之外不太适合。 相反,这本书是要教你如何在必要的命令式代码之上使用纯函数的设计策略。
例如,你需要在一段文本中找出头四个只含有字母的单词,稚嫩一些的写法会是这样:
var words = [], count = 0; text = myString.split(' '); for (i=0; count < 4, i < text.length; i++) { if (!text[i].match(/[0-9]/)) { words = words.concat(text[i]); count++; } } console.log(words);
函数式编程会写成这样:
var words = []; var words = myString.split(' ').filter(function(x){ return (! x.match(/[1-9]+/)); }).slice(0,4); console.log(words);
如果有一个函数式编程的工具库,代码可以进一步被简化:
Um festzustellen, ob eine Funktion funktionaler geschrieben werden kann, suchen Sie nach Schleifen und temporären Variablen, wie z. B. den Variablen „words“ und „count“ im vorherigen Beispiel. Wir können Schleifen und temporäre Variablen häufig durch Funktionen höherer Ordnung ersetzen, was wir später in diesem Kapitel untersuchen werden.
Ist Javascript eine funktionale Programmiersprache?
Nun müssen wir uns noch eine letzte Frage stellen: Ist Javascript eine funktionale Sprache oder eine nicht funktionale Sprache?
Javascript ist wohl die beliebteste, aber am wenigsten verstandene funktionale Programmiersprache der Welt. Javascript ist eine funktionale Programmiersprache in C. Seine Syntax ähnelt definitiv der von C, was bedeutet, dass die Blocksyntax und die Infix-Wortreihenfolge von C verwendet werden. Und es hat den schlechtesten Namen aller lebenden Sprachen. Sie müssen es sich nicht vorstellen, um zu sehen, wie viele Menschen über die Beziehung zwischen Javascript und Java verwirrt sind, als ob der Name darauf hindeutet, was es sein wird! Aber eigentlich hat es sehr wenig mit Java gemeinsam. Es gibt jedoch immer noch einige Ideen, um Javascript in eine objektorientierte Sprache zu zwingen. Beispielsweise haben Bibliotheken wie Dojo und easy.js viel Arbeit geleistet, um zu versuchen, Javascript zu abstrahieren, um es für die objektorientierte Programmierung geeignet zu machen. Javascript stammt aus den 1990er Jahren, als die Welt lautstark nach objektorientierter Programmierung verlangte. Uns wurde gesagt, dass Javascript eine objektorientierte Sprache sei, weil wir es wollten, aber tatsächlich war es das nicht.
Seine wahre Identität lässt sich auf seine Prototypen zurückführen: Scheme und Lisp, zwei klassische funktionale Programmiersprachen. Javascript war schon immer eine funktionale Programmiersprache. Seine Funktionen sind Bürger erster Klasse und können verschachtelt werden, es verfügt über Abschlüsse und zusammengesetzte Funktionen und es ermöglicht Rationalisierung und Monaden. All dies ist der Schlüssel zur funktionalen Programmierung. Hier sind einige weitere Gründe, warum Javascript eine funktionale Sprache ist:
• Das Lexikon von Javascript bietet die Möglichkeit, Funktionen als Parameter zu übergeben, verfügt über ein Typinferenzsystem und unterstützt anonyme Funktionen, Funktionen höherer Ordnung, Abschlüsse usw. Diese Eigenschaften sind entscheidend für die Struktur und das Verhalten, die die funktionale Programmierung ausmachen.
• Javascript ist keine reine objektorientierte Sprache. Die meisten seiner objektorientierten Entwurfsmuster werden durch das Kopieren von Prototypobjekten vervollständigt. European Computer Manufacturers Association Script (ECMAScript) – die offizielle Form und Standardimplementierung von Javascript – enthält in Version 4.2.1 der Spezifikation die folgende Aussage:
„Javascript hat keine echten Klassen wie C, Smalltalk und Java, unterstützt aber Konstruktoren zum Erstellen von Objekten. Im Allgemeinen wird in klassenbasierten objektorientierten Sprachen der Zustand von Instanzen übertragen, Methoden werden von Klassen übertragen und die Vererbung erfolgt.“ nur für Struktur und Verhalten. In EMACScript werden Status und Methoden von Objekten getragen und Struktur, Verhalten und Status werden vererbt
Mit anderen Worten, Javascript ist tatsächlich keine rein funktionale Sprache. Es mangelt an verzögerter Auswertung und integrierten unveränderlichen Daten. Dies liegt daran, dass die meisten Dolmetscher namentlich und nicht auf Abruf aufgerufen werden. Aufgrund der Art und Weise, wie Tail Calls verarbeitet werden, ist Javascript auch nicht besonders gut im Umgang mit Rekursionen. Aber all diese Probleme können mit ein paar kleinen Überlegungen gemildert werden. Eine nicht strikte Auswertung, die unendliche Sequenzen und eine verzögerte Auswertung erfordert, kann über eine Bibliothek namens Lazy.js erreicht werden. Unveränderlichkeit kann einfach durch Programmierkenntnisse erreicht werden, ist jedoch nicht auf das Sprachniveau beschränkt, sondern erfordert Selbstdisziplin des Programmierers. Die Eliminierung der Schwanzrekursion kann durch eine Methode namens Trampolining erreicht werden. Diese Probleme werden in Kapitel 6 erläutert.
Es gab schon immer viele Debatten darüber, ob Javascript eine funktionale Sprache, eine objektorientierte Sprache, beides oder keines von beiden ist, und diese Debatten werden weitergehen.
Schließlich ist funktionale Programmierung eine Möglichkeit, durch clevere Änderungen, Kombinationen und Verwendung von Funktionen prägnanten Code zu schreiben. Und Javascript bietet eine gute Möglichkeit, dies zu erreichen. Wenn Sie das volle Potenzial von Javascript wirklich ausschöpfen möchten, müssen Sie lernen, es als funktionale Sprache zu nutzen.