javascript設計模式–封裝和資訊隱藏(上)

來源:互聯網
上載者:User

  今天博文關注的是javascript中的封裝,文章內容來自《pro javascript design patterns》(有興趣的朋友可以直接去下)和自己對這一問題的理解。

  本文分上下兩部分,上部講基本模式(basic patterns):完全暴露法,底線標記法和使用閉包;下部講進階模式(Advanced Patterns),如何?靜態方法和屬性,常量還有其他一些知識點。

 

  封裝是物件導向語言很基本也是很有用的特性,雖然javascript也可以稱的上是物件導向語言,但他對封裝的支援並不是很好,不像其他語言,只要使用private、protected就可以實現。但這並不是說就沒有辦法了,下面我就介紹下如何在javascript中實現封裝。

  一、基本模式(basic patterns),主要包括三種方式:完全暴露法,底線標記法和使用閉包。(閉包是個很重要,也是很難的概念,有興趣的朋友可以去網上找資料,我部落格裡也轉載了別人的文章)。

  這裡我們以book類作為例子,需要建立和初始化book類。

// Book(isbn, title, author)var theHobbit = new Book('0-395-07122-4', 'The Hobbit', 'J. R. R. Tolkien');theHobbit.display(); // Outputs the data by creating and populating an HTML element.

 

  1.完全暴露法:

  建立book類可以用最傳統的建構函式方式,

var Book = function(isbn, title, author) {  if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');
  this.isbn = isbn;
  //代碼中 || 的作用是 如果title無值,則會把'No title specified'賦給 this.title。這種方式很好用,大家可以在自己的代碼中使用。
  this.title = title || 'No title specified';
  this.author = author || 'No author specified';}
Book.prototype = {
  //驗證isbn函數
  checkIsbn: function(isbn) {
    ...
  },
  //擷取isbn
  getIsbn: function() {
    return this.isbn;
  },
  //設定isbn
  setIsbn: function(isbn) {
    if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');
      this.isbn = isbn;
  },
  //擷取title
  getTitle: function() {
    return this.title;
  },
  //設定title
  setTitle: function(title) {
    this.title = title || 'No title specified';
  },
  //擷取作者
  getAuthor: function() {
    return this.author;
  },
  //設定作者
  setAuthor: function(author) {
    this.author = author || 'No author specified';
  },
  //顯示函數
  display: function() {
    ...
  }
};

  代碼有點多,我在這裡簡單講解下。javascript中建立類和c#,java有點不同,c#,java會把所有方法和屬性包在一個類檔案裡面,比如說

public class book(){    private string isbn;    public string ISBN    {        set
{
      this.isbn=value;
     }
     get
     {
      return this.isbn;
     }
  } ... private bool CheckIsbn(string isdn) { ...... } ...... public void Display() { ...... }}

  javascript也可以用這種方式,但是推薦使用我上面使用的把屬性定義到類定義函數(或者叫建構函式),方法定義到prototype對象中,這種做法效能要好些,至於原因大家可以去google。
  上面的js代碼想實現的功能是,定義一個book類,類裡麵包括三個私人變數(或者叫屬性)isbn,title,author,一個私人方法checkIsbn,幾個公有方法getIsdn,setIsdn,...display。想法是好的,但是現實是殘酷的,其實那些私人屬性或者方法根本一點都不私人。比如說,theHobbit.isbn = '978-0261103283';你可以用這種方式為isbn賦值,不會報錯而且絕對成功。原因就是javascript沒有private方式去實現對特定對象的私人化。此外這種實現方式在使用時也會造成困惑,到底類的建立者想暴露哪些屬性和方法呢?下面介紹第一種改進辦法,底線標記法。

  2.底線標記法:

var Book = function(isbn, title, author) {  // Constructor code.
  this.setIsbn(isbn);  this.setTitle(title);
  this.setAuthor(author);
} Book.prototype = {   
  //驗證isbn函數   
  _checkIsbn: function(isbn) {
    ...
  },   
  //擷取isbn   
  getIsbn: function() {     
    return this._isbn;   
  },   
  //設定isbn   
  setIsbn: function(isbn) {     
    if(!this._checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');       
    this._isbn = isbn;   
  },   
  ...  
  //顯示函數   
  display: function() {     
  ...   
  }
};

  其實就是在所有想實現私人的屬性或者方法前面加了底線_,沒別的操作。這種方法並沒有實現真正的私人化,theHobbit._isbn = '978-0261103283';這樣操作照樣成功,這種方式最大的意義在於告訴類的使用者,作者本意上想暴露哪些對象,不想暴露哪些。但是使用者是否按照作者的想法去做,作者是控制不了的。

  那有沒有辦法實現真正的私人化呢,答案是有的,就是利用閉包。

  3.使用閉包:

   javascript之所以能實現真正的封裝,是和他特有的函數範圍,函數支援內建函式,還有閉包分不開的。大家可以去網上搜集相關知識加深理解。

   下面首先說的就是函數範圍,在javascript中如果在一個函數內部定義了一個變數,那麼函數外部是沒有辦法訪問的。其實在javascript中實現私人屬性或者方法就是利用了它這一特殊屬性。例子:

function foo() {  var a = 10;  function bar() {    a *= 2;  }  bar();  return a;}

  在上面的例子中函數foo在內部定義了變數a和方法bar,在foo外部是無法訪問到a和bar的,但是因為a和bar都定義在foo內部,但bar是可以訪問到a的。那麼有沒有辦法能在foo外部存取到bar呢,答案是有的,就是使用閉包。

function foo() {  var a = 10;  function bar() {    a *= 2;    return a;  }  return bar;}

var baz = foo(); // baz is now a reference to function bar.
baz(); // returns 20.
baz(); // returns 40.
baz(); // returns 80.
var blat = foo(); // blat is another reference to bar.
blat(); // returns 20, because a new copy of a is being used.

  這就是在前面提到的javascript函數支援內建函式。內建函式bar可以訪問私人變數a,函數foo又把內建函式bar拋出給baz,baz就可以訪問到內部變數a了,這就實現了閉包。大家一看也就明白了,這樣其實就實現了私人變數和方法。回到我們前面的book例子,實現如下:

var Book = function(newIsbn, newTitle, newAuthor) { 
  // implements Publication  // Private attributes.  var isbn, title, author;  // Private method.  function checkIsbn(isbn) {    ...  }  // Privileged methods.  this.getIsbn = function() {    return isbn;  };  this.setIsbn = function(newIsbn) {    if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');    isbn = newIsbn;  };  this.getTitle = function() {    return title;  };  this.setTitle = function(newTitle) {    title = newTitle || 'No title specified';  };  this.getAuthor = function() {    return author;  };  this.setAuthor = function(newAuthor) {    author = newAuthor || 'No author specified';  };  // Constructor code.  this.setIsbn(newIsbn);  this.setTitle(newTitle);  this.setAuthor(newAuthor);};// Public, non-privileged methods.Book.prototype = {  display: function() {    ...  }};

  上述代碼就實現了 isbn, title, author和checkIsbn的私人化,外部是決定不能直接存取到的。如需訪問 isbn, title, author只能通過對象級的方法getTitle,setTitle...。比如要給isbn賦值,只能用theHobbit.setIsbn = '978-0261103283';,如果你還用theHobbit._isbn = '978-0261103283';,對不起要報錯了。

  好了,今天的內容就講到這裡了,希望對大家有協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.