函數型 VS 物件導向型的javascript程式設計

來源:互聯網
上載者:User

原文點擊這裡

靈活的js語言可以輕易的就完成截然相反的兩種編程模式–函數型程式設計和物件導向的程式設計。

js原生的支援將函數當做變數來處理。你可以將一個函數賦值給一個變數,然後把他傳給其他的變數。抽象的說,我們可以認為js的函數是一個特殊的變數:只不過他的形式是“函數”。

js原生的也提供對象。在js中,對象可以認為是一系列平面化的屬性值和方法。他們看起來像是一個資料字典,而不像你在其他諸如java、c++、c#中看到的對象那樣。在經典的物件導向編程中,類表示可以通過new操作符來產生一個執行個體的模板。但是在js中,沒有可以當做藍本來產生對象的。在js中,一個對象的藍本更像是一個資料字典。所以在js中,你可以建立對象,然後可以在對象中儲存資料。當然,js的對象也提供一定程度的物件導向的特性,比如封裝和繼承。

js開發越來越熱,兩種模式的優劣是什嗎?js對兩種模式都支援,但是問題的答案得你自己來弄清楚。它兩種都支援,但並不是某一種特別的合適。OOP的js架構和函數型的js都同時存在。

函數型程式設計簡介

函數型程式設計中,每個程式碼片段都是在”function”之上建立的,這與傳統的OOP建立在”class”之上是不同的。一個函數只是對輸入的展現的一種操作。一個函數只是接收一些輸入,然後返回一些輸出,其他的都是隱藏起來的。

在函數型程式設計中,你通過在一個函數中調用其他的函數來完成程式的輸入與輸出。這通常都沒有可以處理輸入、儲存資料以及一系列的狀態更新的那一層。函數就像一個數值一樣,可以作為參數傳遞給其他函數。

javascript與函數型程式設計

需要明確的一個事實是:js並不是像F#那樣真正的函數型程式設計語言,雖然他有一些函數型程式設計模式的特性。利用這些特性,你也可以用js做很好的工作。到今天為止,使用jQuery就是這種模式最廣泛的應用了。

匿名函數是函數型程式設計的精華之所在。匿名函數是lambda計算式的另一種形式,一種可以適配經流行的編碼風格。

123
function (x,y){     return x + y;}

普通函數和匿名的函數的唯一區別就在於名字。在函數的上下文中,當你只是需要函數的傳回值作為參數來使用的時候,並不是非得要給他一個函數名。通過下面這個例子我們來看看:

123456789101112131415161718
// 一個用來計算和的函數var CalcTotal = function(x, y) {   return x + y;}; // 增加稅率var AddTaxes = function(x) {  return x * 1.2;}; // 最終的計算函數var CalcTotalPlusTaxes = function (fnCalcTotal, fnAddTaxes, x, y) {     return fnAddTaxes(fnCalcTotal(x, y));}; // 執行var result = CalcTotalPlusTaxes(CalcTotal, AddTaxes, 40, 60);alert(result);

需要注意的是,你也可以使用匿名函數,而不是非得通過一個中間變數來傳遞給最終的計算式。

123
alert(     (function(x){return x * 1.2})(100););

將匿名函數看做一個變數,可以很輕鬆的將資料和特性合并在一起。這也給你了一個機會去實驗一些其他的設計原則。當高一級的模組(無論對象還是函數)需要低一級的模組提供的傳回值的時候,就可以將低一級的模組直接當做參數傳過去。很多情況下,這會提高函數參數的可讀性,並且讓代碼更優雅一些,當然,也會讓你在處理複雜事物的時候更加得心應手。

jQuery和函數型程式設計

jQuery在函數型程式設計方面吸引了人們極大的關注。整個jQuery庫都是基於jquery對象或者說$。$是DOM元素的一個封裝,DOM元素也可以通過$()運算式傳遞進去。另外,jQuery支援鏈式操作,每一個函數運行之後都會返回同一個jquery對象。

jQuery非常高效,因為你可以在主要工作是操作DOM元素的WEB編程環境下最大限度的發揮出函數型程式設計的威力。你也許是jQuery的粉絲,並且覺得這種函數式的操作非常贊。但是,這不是需要完全把這種編程模式到處使用的理由。我們通過下面這個jQuery源碼來看個例子:

12345678
jQuery.fn = jQuery.prototype = {    init: function( selector, context ) { ... },       size: function() { return this.length; },       each: function( callback, args ) {        return jQuery.each( this, callback, args );  },       ready: function( fn ) { ... }       :}

可以看到,jQuery對象有他自己的原型,也有一些自有的方法:比如size和each。更有意思的是,當你寫jQuery的外掛程式的時候,你只是給通過添加一個函數擴充了原型方法。至此,所有高效的js編程,都是兩種模式混合的結果。當然jQuery中函數型的模式更加明顯一些。

javascript中的對象

真正物件導向編程中的對象與javascript中的對象有一個很明顯的不同。在物件導向的語言中,類是你要使用的對象的藍本。在javascript中,你所使用的對象的藍本是一個資料字典或者一個函數。當你在js中建立了一個對象,你就擁有一個你可以填進去任何資料的空的資料字典。

之前說過,通過一些方法,你可以建立一些自訂的對象或者繼承自現有的對象。這隻在js中有效。

當你需要通過添加中間的轉化來接近真正的物件導向語言的時候,在js中有兩種辦法:閉包和原型。

在講述那兩種辦法之前,我們先來講講js中的物件類型和他的用法。

你可以通過new關鍵字來建立一個空的對象,然後你可以給這個對象添加進去你想要的內容:

123456789101112131415161718
var person = new Object();person.Name = "Dino";person.LastName = "Esposito";person.BirthDate = new Date(1979,10,17)person.getAge = function() {  var today = new Date();  var thisDay = today.getDate();  var thisMonth = today.getMonth();  var thisYear = today.getFullYear();  var age = thisYear-this.BirthDate.getFullYear()-1;  if (thisMonth > this.BirthDate.getMonth())      age = age +1;  else  if (thisMonth == this.BirthDate.getMonth() &&      thisDay >= this.BirthDate.getDate())      age = age +1;  return age;}

我們現在擁有一個名為person的對象,但是沒有Person對象。在js中,所有的原聲對象都有一個唯讀prototype屬性。通過這個屬性,你可以用來提供一些函數,這些函數在使用new關鍵字的時候,新產生的對象可以與原對象共用這些方法。下面有兩種方法可以在js中實現物件導向編程。

通過閉包實現物件導向

閉包是程式設計語言中的一個基本概念。在js中,閉包是指那些擁有同樣內容相關的變數和方法的一個函數。下面這個例子就是使用閉包來類比一個Person類:

1234567891011121314151617181920
var Person = function(name, lastname, birthdate){   this.Name = name;   this.LastName = lastname;   this.BirthDate = birthdate;    this.getAge = function() {      var today = new Date();      var thisDay = today.getDate();      var thisMonth = today.getMonth();      var thisYear = today.getFullYear();      var age = thisYear-this.BirthDate.getFullYear()-1;      if (thisMonth > this.BirthDate.getMonth())          age = age +1;      else         if (thisMonth == this.BirthDate.getMonth() &&             thisDay >= this.BirthDate.getDate())             age = age +1;      return age;   }}

可以看出,閉包就是父類的建構函式。在閉包模式中,構造器包含類成員的聲明,並且這些成員都是封裝起來的。另外,成員都是基於執行個體的,所以會消耗記憶體。如何使用呢:

12
var p = new Person('Rock','ux',new Date());alert(p.name + 'is' + p.getAge());

閉包模式是完全封裝的,僅此而已。

原型模式的物件導向方法

通過js中prototype對象,你可以定義一個類的結構。下面這個例子用來說明怎樣避免使用閉包來重寫Person類。

12345678910111213141516171819202122232425262728
// 構造器var Person = function(name, lastname, birthdate){    this.initialize(name, lastname, birthdate);} // 成員Person.prototype.initialize(name, lastname, birthdate){     this.Name = name;     this.LastName = lastname;     this.BirthDate = birthdate;}Person.prototype.getAge = function(){     var today = new Date();     var thisDay = today.getDate();     var thisMonth = today.getMonth();     var thisYear = today.getFullYear();     var age = thisYear-this.BirthDate.getFullYear()-1;     if (thisMonth > this.BirthDate.getMonth())         age = age +1;     else        if (thisMonth == this.BirthDate.getMonth() &&            thisDay >= this.BirthDate.getDate())            age = age +1;     return age;}

在原型模式下面,構造器和成員之間結構清晰,但是建構函式是必須的。這裡並沒有私人成員,var關鍵字可以讓其只在閉包中有效。你可以通過定義setter/getter來操作你需要的屬性,但是這些屬性在類外面也是可以直接存取修改的。你可以通過一些特殊的操作(比如添加首碼)來定義私人變數。只是一種辦法而已。

原型模式可以很簡單的實現繼承:

12345
Developer = function Developer(name, lastname, birthdate){   this.initialize(name, lastname, birthdate);}Developer.prototype = new Person();

需要注意的是,你必須通過使用this關鍵字來訪問原型中的相關成員方法。

閉包還是原型?

在原型模式中,所有的成員都是共用的。所以,相比而言,記憶體的開銷要小一些。除去文法方面的不同,通過原型模式定義的類更加接近經典意義上的物件導向語言。

閉包還是原型的選擇還要從效能和瀏覽器的相容性來考慮。原型模式的載入速度不錯,而且在Firefox中效能也很好。(相比而言,閉包模式在IE下面的載入更快一些。)原型模式對於智能感知支援不錯,這樣在一些IDE中(比如VS)就能得到很好的工具支援。原型模式下,你不必通過建立一個執行個體來查看類型資訊,閉包模式下就不行。最後,調試的時候,原型模式可以方便的訪問私人成員,閉包模式下面得多幾步操作才行。

舉個例子,微軟的ajax庫使用的就是原型模式(閉包模式從未被考慮)。

結論

Javascript並不是純粹的函數型或者物件導向的語言。但是他從兩種語言都有借鑒,所以你需要做好一些準備。

如今,Javascript對於編寫用戶端的網頁和行動裝置 App程式來說必不可少。而且現在的指令碼編寫也不像當初這個語言開始使用的時候了。現在我們經常使用js來做用戶端的表單驗證等程式。為了讓開發進程更加的平穩,我們也需要一些js庫。jQuery就是最好的例證。

隨著jQuery大放光芒,函數型變成再次在js語言中相對於物件導向得到了更多的關注。最終,選擇什麼還是在你。你也不必像選擇一種信仰似的選擇一種開發模式,開發中,兩者混合使用是非常常見的事情。

如前所述,如果我是前端開發,我可能會使用jQuery,然後使用一些匿名函數,不去關心什麼自訂的對象。如果我是要自己寫一個js的庫,那麼我肯定會選擇物件導向開發,或者使用閉包模式或者使用原型模式。

點擊查看原文

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.