Javascript函數(shù)式編程簡(jiǎn)單介紹
幾十年來(lái),函數(shù)式編程一直是計(jì)算機(jī)科學(xué)狂熱者的至愛(ài),由于數(shù)學(xué)的純潔性和謎一般的本質(zhì), 它被埋藏在計(jì)算機(jī)實(shí)驗(yàn)室,只有數(shù)據(jù)學(xué)家和有希望獲得博士學(xué)位的人士使用。但是現(xiàn)在,它正經(jīng)歷一場(chǎng)復(fù)興, 這要感謝一些現(xiàn)代語(yǔ)言比如Python,Julia,Ruby,Clojure以及——但不是最后一個(gè)——Javascript。
你是說(shuō)Javascript?這個(gè)WEB腳本語(yǔ)言?沒(méi)錯(cuò)!
Javascript已經(jīng)被證明是一項(xiàng)長(zhǎng)期以來(lái)都沒(méi)有消失的重要的技術(shù)。這主要是由于它擴(kuò)展的一些框架和庫(kù)而使其具有重生的能力, 比如backbone.js,jQuery,Dojo,underscore.js等等。這與Javascript函數(shù)式編程語(yǔ)言的真實(shí)身份直接相關(guān)。 對(duì)Javascript函數(shù)式編程的理解很重要,并且在相當(dāng)長(zhǎng)的一段時(shí)間會(huì)對(duì)各種水平的程序員很有用。
為什么呢?函數(shù)式編程非常強(qiáng)大、健壯并且優(yōu)雅。它對(duì)于大型數(shù)據(jù)結(jié)構(gòu)非常有用并且高效。 Javascript作為一個(gè)客戶(hù)端腳本語(yǔ)言,在應(yīng)對(duì)日益復(fù)雜的網(wǎng)站時(shí),函數(shù)式地操作DOM、 組織API響應(yīng)以及完成一些其它任務(wù)會(huì)非常有好處。
在這本書(shū)里,你將會(huì)學(xué)習(xí)用Javascript進(jìn)行函數(shù)式編程所需要知道的一切:如何用函數(shù)式編程構(gòu)建你的Javascript web應(yīng)用, 如何解鎖Javascript隱藏的力量,如何編寫(xiě)更強(qiáng)大的代碼,并且由于程序更小,使得代碼更容易維護(hù),能夠更快被下載, 并且花費(fèi)更少的開(kāi)支。你還會(huì)學(xué)到函數(shù)式編程的核心概念,以及如何將它們應(yīng)用到Javascript, 還有將Javascript作為函數(shù)式語(yǔ)言時(shí)如何回避一些問(wèn)題,如何在Javascript中混合使用函數(shù)式編程和面向?qū)ο缶幊獭?/p>
不過(guò)在我們開(kāi)始前,先來(lái)做個(gè)實(shí)驗(yàn)。
例子
也許快速舉個(gè)例子是介紹Javascript函數(shù)式編程最好的方式。我們將用Javascript完成一些任務(wù)—— 一個(gè)使用傳統(tǒng)、原生的方法,另一個(gè)使用函數(shù)式編程。然后我們將會(huì)比較這兩種方法。
應(yīng)用——一個(gè)電子商務(wù)網(wǎng)站
為了追求真實(shí)感,我們來(lái)做一個(gè)電子商務(wù)網(wǎng)站,一個(gè)郵購(gòu)咖啡豆的公司。這個(gè)網(wǎng)站會(huì)銷(xiāo)售好幾種類(lèi)型的咖啡, 有不同的品質(zhì),當(dāng)然也有不同的價(jià)格。
命令式方法
首先,我們開(kāi)始寫(xiě)程序。為了讓這個(gè)例子接地氣,我們需要?jiǎng)?chuàng)建一些對(duì)象來(lái)保存數(shù)據(jù)。如果需要的話(huà)我們可以從數(shù)據(jù)庫(kù)里取值。 但是現(xiàn)在我們假設(shè)他們是靜態(tài)定義的:
// create some objects to store the data. var columbian = {  name: 'columbian', basePrice: 5 }; var frenchRoast = { name: 'french roast', basePrice: 8 }; var decaf = { name: 'decaf', basePrice: 6 }; // 我們將使用輔助函數(shù)計(jì)算價(jià)格 // 根據(jù)size打印到一個(gè)HTML的列表中 function printPrice(coffee, size) { if (size == 'small') { var price = coffee.basePrice + 2; } else if (size == 'medium') { var price = coffee.basePrice + 4; } else { var price = coffee.basePrice + 6; } // create the new html list item var node = document.createElement("li"); var label = coffee.name + ' ' + size; var textnode = document.createTextNode(label+' price: $'+price); node.appendChild(textnode); document.getElementById('products').appendChild(node); } // 現(xiàn)在我們只需根據(jù)咖啡的各種價(jià)格和size的組合調(diào)用printPrice函數(shù) printPrice(columbian, 'small'); printPrice(columbian, 'medium'); printPrice(columbian, 'large'); printPrice(frenchRoast, 'small'); printPrice(frenchRoast, 'medium'); printPrice(frenchRoast, 'large'); printPrice(decaf, 'small'); printPrice(decaf, 'medium'); printPrice(decaf, 'large');
如你所見(jiàn),這個(gè)代碼非?;A(chǔ)。如果現(xiàn)在有更多的咖啡種類(lèi)而不只是這三個(gè)改怎么辦?如果有20個(gè),甚至50個(gè)? 如果有更多的size呢?如果有有機(jī)和無(wú)機(jī)之分呢?這將會(huì)很快將代碼量變得巨大無(wú)比!
采用這種方法,我們讓機(jī)器去打印每一種咖啡類(lèi)型和每一個(gè)size。這就是采用這種命令式方法的基本問(wèn)題。
函數(shù)式編程
命令式的代碼一步一步地告訴電腦需要做什么來(lái)解決問(wèn)題,相反,函數(shù)式編程追求用數(shù)學(xué)方式來(lái)描述問(wèn)題, 其余的交給電腦來(lái)做。
通過(guò)更函數(shù)式一些的方式,同樣的應(yīng)用可以這樣來(lái)寫(xiě):
// 從接口中分解數(shù)據(jù)和邏輯 var printPrice = function(price, label) { var node = document.createElement("li"); var textnode = document.createTextNode(label+' price: $'+price); node.appendChild(textnode); document.getElementById('products 2').appendChild(node); } // 為每種咖啡創(chuàng)建函數(shù)對(duì)象 var columbian = function(){ this.name = 'columbian'; this.basePrice = 5; }; var frenchRoast = function(){ this.name = 'french roast'; this.basePrice = 8; }; var decaf = function(){ this.name = 'decaf'; this.basePrice = 6; }; // 為每種size通過(guò)字面量創(chuàng)建對(duì)象 var small = { getPrice: function(){return this.basePrice + 2}, getLabel: function(){return this.name + ' small'} }; var medium = { getPrice: function(){return this.basePrice + 4}, getLabel: function(){return this.name + ' medium'} }; var large = { getPrice: function(){return this.basePrice + 6}, getLabel: function(){return this.name + ' large'} }; // 將所有咖啡的種類(lèi)和size放到數(shù)組里 var coffeeTypes = [columbian, frenchRoast, decaf]; var coffeeSizes = [small, medium, large]; // 創(chuàng)建由上面內(nèi)容組成的新對(duì)象,并把它們放到一個(gè)新數(shù)組里 var coffees = coffeeTypes.reduce(function(previous, current) { var newCoffee = coffeeSizes.map(function(mixin) { // `plusmix`是函數(shù)式的minxin, 見(jiàn)第7章 var newCoffeeObj = plusMixin(current, mixin); return new newCoffeeObj(); }); return previous.concat(newCoffee); },[]); // 現(xiàn)在我們已經(jīng)定義了如何獲得所有咖啡種類(lèi)和size組合方式的價(jià)格,現(xiàn)在可以直接打印它們了 coffees.forEach(function(coffee){ printPrice(coffee.getPrice(),coffee.getLabel()); });
首先需要明確的是這個(gè)代碼更加模塊化了。現(xiàn)在新增一種size或者信新增一個(gè)咖啡種類(lèi)就像下面的代碼這樣簡(jiǎn)單:
var peruvian = function(){ this.name = 'peruvian'; this.basePrice = 11; }; var extraLarge = { getPrice: function(){return this.basePrice + 10}, getLabel: function(){return this.name + ' extra large'} }; coffeeTypes.push(Peruvian); coffeeSizes.push(extraLarge);
咖啡對(duì)象的數(shù)組和size對(duì)象的數(shù)組混合(mix)到了一起,也就是他們的方法和成員變量被組合到了一塊兒 ——通過(guò)一個(gè)叫“plusMinxin”的自定義函數(shù)(詳見(jiàn)第七章)。這些咖啡類(lèi)型的類(lèi)(columbian, frenchRoast, decaf)包含了成員變量, 而這些size對(duì)象(small, medium, large)包含了獲取名稱(chēng)和計(jì)算價(jià)格的方法。 ”混合”(minxing)這個(gè)動(dòng)作通過(guò)一個(gè)map操作來(lái)起作用,也就是對(duì)數(shù)組中的每一個(gè)成員執(zhí)行一個(gè)純函數(shù)并返回一個(gè)新的函數(shù), 然后這些返回的函數(shù)被放到了一個(gè)reduce函數(shù)中被操作,reduce也是一個(gè)高階函數(shù),和map有些像, 只是reduce把數(shù)組里的所有元素處理后組合到了一個(gè)東西里面。最終,新的數(shù)組包含了所有可能的種類(lèi)和size的組合, 這個(gè)數(shù)組通過(guò)forEach方法遍歷,forEach也是一個(gè)高階函數(shù),它會(huì)讓數(shù)組里面每一個(gè)對(duì)象作為參數(shù)執(zhí)行一遍回調(diào)函數(shù)。 在這個(gè)例子里,這個(gè)回調(diào)函數(shù)是一個(gè)匿名函數(shù),它獲取這些對(duì)象后,以對(duì)象的getPrice()和getLabel() 兩個(gè)方法的返回值作為參數(shù)調(diào)用printPrice函數(shù)。
實(shí)際上,我們可以讓這個(gè)例子更加函數(shù)式:去掉coffees變量,并將函數(shù)串到一起鏈?zhǔn)秸{(diào)用,這也是函數(shù)式編程的一個(gè)小技巧。
coffeeTypes.reduce(function(previous, current) { var newCoffee = coffeeSizes.map(function(mixin) { // `plusMixin` function for functional mixins, see Ch.7 var newCoffeeObj = plusMixin(current, mixin); return new newCoffeeObj(); }); return previous.concat(newCoffee); },[]).forEach(function(coffee) { printPrice(coffee.getPrice(),coffee.getLabel()); });
這樣,控制流沒(méi)有像命令式代碼那樣從頭到尾的順序進(jìn)行。在函數(shù)式編程里,map函數(shù)和其它高階函數(shù)代替了for和while循環(huán), 只有少量關(guān)鍵的代碼是在順序執(zhí)行。 這使得新接觸的人在閱讀這樣范式的代碼有些困難,但是一旦你能夠欣賞它,你就會(huì)發(fā)現(xiàn)這根本沒(méi)啥難的, 而且這樣寫(xiě)看起來(lái)更好。
這個(gè)例子僅僅是剛開(kāi)始展露Javascript中函數(shù)式編程能做什么。通過(guò)這本書(shū),你將會(huì)看到更多函數(shù)式實(shí)現(xiàn)的強(qiáng)悍的例子。
總結(jié)
首先,采用函數(shù)式風(fēng)格的優(yōu)點(diǎn)已經(jīng)明確了。 其次,不要害怕函數(shù)式編程。的確,它往往被認(rèn)為是編程語(yǔ)言的純邏輯形式,但是我們不需要理解lambda演算也能夠在日常任務(wù)中應(yīng)用它。 實(shí)際上,通過(guò)把我們的程序拆分成小的片段,它們變得更容易被理解、維護(hù),也更加可靠。 map和reduce函數(shù)是Javascript中不太被知道的內(nèi)建函數(shù),然而我們將要關(guān)注它們。
Javascript是一個(gè)腳本語(yǔ)言,可交互,易使用,不需要編譯。我們甚至不需要下載任何開(kāi)發(fā)軟件, 你最喜歡的瀏覽器就可以作為開(kāi)發(fā)環(huán)境的解釋器。
感興趣嗎?好,我們開(kāi)始!
- Javascript中的高階函數(shù)介紹
- Javascript 高階函數(shù)使用介紹
- JS高階函數(shù)原理與用法實(shí)例分析
- JavaScript函數(shù)式編程(Functional Programming)純函數(shù)用法分析
- JavaScript函數(shù)式編程(Functional Programming)聲明式與命令式實(shí)例分析
- JavaScript 函數(shù)式編程實(shí)踐(來(lái)自IBM)
- javascript函數(shù)式編程實(shí)例分析
- 探究JavaScript函數(shù)式編程的樂(lè)趣
- 《JavaScript函數(shù)式編程》讀后感
- JavaScript的函數(shù)式編程基礎(chǔ)指南
- 淺談javascript函數(shù)式編程
- JavaScript函數(shù)式編程(Functional Programming)高階函數(shù)(Higher order functions)用法分析
相關(guān)文章
uniapp安卓本地寫(xiě)入讀取文件簡(jiǎn)單示例
這篇文章主要給大家介紹了關(guān)于uniapp安卓本地寫(xiě)入讀取文件的相關(guān)資料,在uniapp中可以使用uni-app提供的API實(shí)現(xiàn)本地文件讀取和寫(xiě)入,需要的朋友可以參考下2023-11-11JS實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)鏈接的幾種方式匯總
這篇文章主要介紹了JS實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)鏈接的幾種方式,簡(jiǎn)單總結(jié)了幾種頁(yè)面跳轉(zhuǎn)功能的實(shí)現(xiàn),有使用js跳轉(zhuǎn)頁(yè)面,返回上一次預(yù)覽界面及button按鈕添加事件跳轉(zhuǎn),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-01-01淺談JavaScript中定義變量時(shí)有無(wú)var聲明的區(qū)別
這篇文章主要介紹了JavaScript中定義變量時(shí)有無(wú)var聲明的區(qū)別分析以及示例分享,需要的朋友可以參考下2014-08-08JavaScript繼承基礎(chǔ)講解(原型鏈、借用構(gòu)造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承)
這篇文章主要介紹了JavaScript繼承基礎(chǔ)講解,原型鏈、借用構(gòu)造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承,需要的朋友可以參考下2014-08-08js實(shí)現(xiàn)當(dāng)鼠標(biāo)移到表格上時(shí)顯示這一格全部?jī)?nèi)容的代碼
下面小編就為大家?guī)?lái)一篇js實(shí)現(xiàn)當(dāng)鼠標(biāo)移到表格上時(shí)顯示這一格全部?jī)?nèi)容的代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06avascript中的自執(zhí)行匿名函數(shù)應(yīng)用示例
javascript中的自執(zhí)行匿名函數(shù)可以用它創(chuàng)建命名空間,只要把自己所有的代碼都寫(xiě)在這個(gè)特殊的函數(shù)包裝內(nèi),那么外部就不能訪(fǎng)問(wèn),除非你允許2014-09-09生成html靜態(tài)文件后的分頁(yè)(客戶(hù)端版)
生成html靜態(tài)文件后的分頁(yè)(客戶(hù)端版)...2006-07-07