首頁 > web前端 > js教程 > 主體

Javascript函數式程式設計簡單介紹_javascript技巧

WBOY
發布: 2016-05-16 15:36:55
原創
1170 人瀏覽過

幾十年來,函數式程式設計一直是電腦科學狂熱者的至愛,由於數學的純潔性和謎一般的本質, 它被埋藏在電腦實驗室,只有數據學家和有希望獲得博士學位的人士使用。但現在,它正經歷一場復興, 這要感謝一些現代語言例如Python,Julia,Ruby,Clojure以及——但不是最後一個——Javascript。

你是說Javascript?這個WEB腳本語言?沒錯!

Javascript已經被證明是一項長期以來都沒有消失的重要的技術。這主要是由於它擴展的一些框架和函式庫而使其具有重生的能力, 例如backbone.js,jQuery,Dojo,underscore.js等等。這與Javascript函數式程式語言的真實身分直接相關。 對Javascript函數式程式設計的理解很重要,並且在相當長的一段時間會對各種程度的程式設計師很有用。

為什麼呢?函數式程式設計非常強大、健壯且優雅。它對於大型資料結構非常有用且有效率。 Javascript作為一個客戶端腳本語言,在應對日益複雜的網站時,函數式地操作DOM、 組織API回應以及完成一些其它任務會非常有好處。

在這本書裡,你將會學習用Javascript進行函數式程式設計所需知道的一切:如何用函數式程式設計建立你的Javascript web應用, 如何解鎖Javascript隱藏的力量,如何寫出更強大的程式碼,並且由於程式更小,使得程式碼更容易維護,能夠更快被下載, 並且花費更少的開支。你也會學到函數式程式設計的核心概念,以及如何將它們應用到Javascript, 還有Javascript作為函數式語言時如何迴避一些問題,如何在Javascript中混合使用函數式程式設計和物件導向程式設計。

不過在我們開始前,先來做個實驗。

範例

也許快速舉個例子是介紹Javascript函數式程式設計最好的方式。我們將用Javascript完成一些任務- 一個使用傳統、原生的方法,另一個使用函數式程式設計。然後我們將會比較這兩種方法。

應用程式-一個電子商務網站

為了追求真實感,我們來做一個電子商務網站,一個郵購咖啡豆的公司。這個網站會銷售好幾種類型的咖啡, 有不同的品質,當然也有不同的價格。

命令式方法

首先,我們開始寫程式。為了讓這個範例接地氣,我們需要建立一些物件來保存資料。如果需要的話我們可以從資料庫裡取值。 但現在我們假設他們是靜態定義的: 

 // 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
};
// 我们将使用辅助函数计算价格
// 根据size打印到一个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);
}
// 现在我们只需根据咖啡的各种价格和size的组合调用printPrice函数
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');
登入後複製

如你所見,這個程式碼非常基礎。如果現在有更多的咖啡種類而不只是這三個改怎麼辦?如果有20個,甚至50個? 如果有更多的size呢?如果有有機和無機之分呢?這將很快將程式碼量變得巨大無比!

採用這種方法,我們讓機器列印每種咖啡類型和每一個size。這就是採用這種命令式方法的基本問題。

函數式程式設計

命令式的程式碼一步一步地告訴電腦需要做什麼來解決問題,相反,函數式程式設計追求用數學方式來描述問題, 其餘的交給電腦來做。

透過更函數式一些的方式,同樣的應用可以這樣寫:

// 从接口中分解数据和逻辑
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);
}
// 为每种咖啡创建函数对象
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通过字面量创建对象
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'}
};
// 将所有咖啡的种类和size放到数组里
var coffeeTypes = [columbian, frenchRoast, decaf];
var coffeeSizes = [small, medium, large];
// 创建由上面内容组成的新对象,并把它们放到一个新数组里
var coffees = coffeeTypes.reduce(function(previous, current) {
 var newCoffee = coffeeSizes.map(function(mixin) {
  // `plusmix`是函数式的minxin, 见第7章
  var newCoffeeObj = plusMixin(current, mixin);
  return new newCoffeeObj();
 });
 return previous.concat(newCoffee);
},[]);
// 现在我们已经定义了如何获得所有咖啡种类和size组合方式的价格,现在可以直接打印它们了
coffees.forEach(function(coffee){
 printPrice(coffee.getPrice(),coffee.getLabel());
});
登入後複製

首先需要明確的是這個程式碼更加模組化了。現在新增一種size或信新增一個咖啡種類就像下面的程式碼這樣簡單:

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);
登入後複製

咖啡对象的数组和size对象的数组混合(mix)到了一起,也就是他们的方法和成员变量被组合到了一块儿 ——通过一个叫“plusMinxin”的自定义函数(详见第七章)。这些咖啡类型的类(columbian, frenchRoast, decaf)包含了成员变量, 而这些size对象(small, medium, large)包含了获取名称和计算价格的方法。 ”混合”(minxing)这个动作通过一个map操作来起作用,也就是对数组中的每一个成员执行一个纯函数并返回一个新的函数, 然后这些返回的函数被放到了一个reduce函数中被操作,reduce也是一个高阶函数,和map有些像, 只是reduce把数组里的所有元素处理后组合到了一个东西里面。最终,新的数组包含了所有可能的种类和size的组合, 这个数组通过forEach方法遍历,forEach也是一个高阶函数,它会让数组里面每一个对象作为参数执行一遍回调函数。 在这个例子里,这个回调函数是一个匿名函数,它获取这些对象后,以对象的getPrice()和getLabel() 两个方法的返回值作为参数调用printPrice函数。

实际上,我们可以让这个例子更加函数式:去掉coffees变量,并将函数串到一起链式调用,这也是函数式编程的一个小技巧。

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());
});
登入後複製

这样,控制流没有像命令式代码那样从头到尾的顺序进行。在函数式编程里,map函数和其它高阶函数代替了for和while循环, 只有少量关键的代码是在顺序执行。 这使得新接触的人在阅读这样范式的代码有些困难,但是一旦你能够欣赏它,你就会发现这根本没啥难的, 而且这样写看起来更好。

这个例子仅仅是刚开始展露Javascript中函数式编程能做什么。通过这本书,你将会看到更多函数式实现的强悍的例子。

总结

首先,采用函数式风格的优点已经明确了。 其次,不要害怕函数式编程。的确,它往往被认为是编程语言的纯逻辑形式,但是我们不需要理解lambda演算也能够在日常任务中应用它。 实际上,通过把我们的程序拆分成小的片段,它们变得更容易被理解、维护,也更加可靠。 map和reduce函数是Javascript中不太被知道的内建函数,然而我们将要关注它们。

Javascript是一个脚本语言,可交互,易使用,不需要编译。我们甚至不需要下载任何开发软件, 你最喜欢的浏览器就可以作为开发环境的解释器。

感兴趣吗?好,我们开始!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板