国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Javascript 設計模式讀書筆記(二)——封裝,簡單的創建對象模式

lentrue / 3263人閱讀

摘要:創建對象中,創建對象的基本模式有三種。因此,在設計構造函數時,需要進行慎重考慮。因此在中,這種問題被稱作繼承破壞封裝。靜態成員每個只有一份,直接通過類對象進行訪問。

什么是封裝

找工作時一些公司給了offer后我就想知道真正拿到手的是多少,畢竟賦稅繁重。但各種稅也好,五險一金也好我實在是弄不清楚,于是我就會在網上的一些稅后收入計算器上進行計算,只需要填寫一些基本信息,比如稅前收入,所在地區等等,就能夠獲得詳細的結果,包括各種稅收的詳細數值。在這個過程中,我只是按照接口給定的要求進行了數據的輸入,具體計算過程我并不知道。也就是說,在這個程序內部,數據表現形式和實現細節是隱藏的,這在某種意義上也是封裝的一種。

在Javascript中,對象中的細節有時也需要隱藏,但JS不像其他的靜態語言,比如Java,一樣,有private這樣的關鍵字。那么在Javascript中,就可以用閉包的概念來創建只能從對象內部訪問的方法和屬性。

在使用接口實現信息隱藏的過程中,同時也是使用了接口的概念。好比火影里的通靈術,人與動物簽訂契約,進行某種交換。這中間的溝通渠道不變,簽訂契約的人就可以隨時隨地進行通靈。一個類中,應該定義足夠的安全的接口。然而在JS中,語言特性非常靈活,類中的公有方法和私有方法實際是一樣的。因此,在實現類的時候,應該避免公開未定義于接口的方法。

創建對象

Javascript中,創建對象的基本模式有三種。
1. 直接創建 對象中的所有方法都是公有的,可以公開訪問。
2. 使用下劃線 在私有方法名稱前加下劃線,表示該方法私有。
3. 使用閉包 閉包可以創建真正意義上的私有成員,這些成員只能通過特定方法訪問。

直接創建

所謂直接創建,就是按照傳統的方式創建一個類,構造器是一個函數,屬性和方法全部公開,比如:

var Fruit = function(color, weight) {
  this.color = color || "orange";
  this.weight = weight || 150;
}

Fruit.prototype.boom = function() {
  ...  
}

這種方法一般來說沒什么問題,但是當其原型上的方法boom對自身的屬性color或者weight有一定依賴,而構造時傳入的參數不符合一定要求時就會出錯。但如果構造時沒有出錯則所有方法應該能正常工作才是。

當然這個問題可以在構造對象時就對傳入的參數進行驗證,也不算太嚴重。然而另一個問題在于,即使能對參數進行驗證,任何程序員還是能夠隨意修改屬性的值。為了解決這個問題,可以設計一個數據的取值器和賦值器。

var Fruit = function(color, weight) {
  this.setColor(color);
  this.setWeight(weight);
}

Fruit.prototype = {
  checkColor: function(color) {
    ...
  },
  setColor: function(color) {
    ...
    this.color = color;
  },
  getColor: function() {
    return this.color;
  },
  ...
}

當程序員之間約定以提供的方法對屬性值進行操作時,操作過程可以相對得到規范。但實際上屬性仍然是公開的,可以被直接設置,這種方法并不能阻止這種行為。

使用下劃線,區別私用成員

此種方法與前一種方法其實是一回事,只是在私用的方法和屬性前加了下劃線表示它是私用的。

var Fruit = function(color, weight) {
  this.setColor(color);
  this.setWeight(weight);
}

Fruit.prototype = {
  _checkColor: function(color) {
    ...
  },
  setColor: function(color) {
    ... // 此處對輸入的數據進行驗證,不能通過驗證就拋出異常
    this._color = color;
  },
  getColor: function() {
    return this._color;
  },
  ...
}

這種方法有助于防止對私用方法的無意使用,但無法保證程序員不有意使用它們。

使用閉包

借助閉包就可以創建只允許特定函數訪問的變量了,私用屬性的創建方法即是在構造函數的作用域中創建變量即可,這些變量可以被該作用域中的所有函數訪問。

var Fruit = function(newColor, weight) {
  var color, weight;

  // 私用方法
  function _checkColor = function(color) {
    ...
  }

  // 特權方法
  this.getColor = function() {
    return color;
  };

  this.setColor = function(newColor) {
    ... // 驗證輸入
    color = newColor;
  }

  // 構造過程代碼
  this.setColor(newColor);
}

借助this關鍵字創建的方法就是特權方法了,它們是公開方法,同時也能夠訪問私有變量。如果需要創建一些不需要訪問私有屬性的方法的話,可以在Fruit.prototype上進行創建。通過這種方式創建的方法,不能直接訪問私有變量,但是可以通過getColor這樣的特權方法進行間接訪問。

當然這種方式也有弊端,如果特權方法過多,會占用較多內存,因為通過構造函數創建的實例都保存了特權方法的副本,而原型上的方法只有一份。因此,在設計構造函數時,需要進行慎重考慮。

另一個問題就在于這樣的方法無法作用于需要創建子類的場景,由于特權方法都是新的副本,所以子類無法訪問超類的任何私用屬性或方法。因此在Javascript中,這種問題被稱作“繼承破壞封裝”(inheritance breaks encapsulation)。

高級創建對象模式初探

以上的三種方法屬于創造對象的基本方法,但要實現一些高級的創建對象模式,有必要先了解一些概念。

靜態方法和屬性

前述的閉包創建對象法可以創建私用屬性和方法,但是這樣的話,這些屬性在創建子類時會同時創建副本存于子類,造成內存的浪費。對于一些只需要在類層面進行操作和訪問的屬性,可以利用閉包創建靜態成員。靜態成員每個只有一份,直接通過類對象進行訪問。

仍然以之前的Orange類為例,使用閉包特性添加一些靜態成員:

var Orange = (function() {
  // 私用靜態屬性
  var numOfOranges = 0;

  // 私用靜態方法
  function checkColor() {
    ...
  }

  // 返回構造器
  return function(newColor, weight) {
    var color, weight;

    // 特權方法
    this.getColor = function() {
      return color;
    };
    this.setColor = function(newColor) {
      ...
      color = newColor;
    }

    // 構造器代碼
    numOfOrange++;
    if (numOfOrange > 100) {
      throw new Error("Only 100 instances of Orange can be created.");
    }

    this.setColor(newColor);
  }
})();

// 公開靜態方法
Orange.turnToJuice = function() { // 不添加在Orange的prototype上
  ...
};

// 公開的非特權方法
Orange.prototype = {
  checkWeight: function() {
    ...
  }
};

這與之前的閉包創建類的最大區別在于構造器由一個普通函數變成了一個內嵌函數,通過一個自執行函數的返回值賦給Orange。在實例化Orange時,調用的是返回的內嵌函數,外層函數只是一個用來存放靜態私用成員的閉包。在構造器中的特權方法可以訪問構造器之外的靜態屬性和方法,而靜態方法不能訪問任何定義在構造器中的私用屬性。

常量

常量就是不能被修改的變量,利用靜態屬性可以在Javascript中模擬常量。對常量只創建作為取值器的靜態方法,而不創建賦值器,在外圍作用域中也不能訪問到常量:

var Class = (function() {
  // 常量
  var CONST = 100;

  // 構造器
  var constructorFunc = function(param) {
    ...
  };

  // 靜態方法,取值器
  constructorFunc = function() {
    return CONST;
  };

  return constructorFunc;
})();
封裝之利弊 封裝之利

保護內部數據,只對外提供取值器和賦值器,便于重構。減少模塊間耦合。

封裝之弊

難以進行單元測試,外部測試無法訪問到內部變量和方法。不過如公用方法可以間接訪問私用方法的話,可以對私用方法進行間接單元測試。

實現過程較為復雜,調試難度比較大。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87512.html

相關文章

  • JavaScript設計模式與開發實踐》讀書筆記

    摘要:訂閱模式的一個典型的應用就是后面會寫一篇相關的讀書筆記。享元模式享元模式的核心思想是對象復用,減少對象數量,減少內存開銷。適配器模式對目標函數進行數據參數轉化,使其符合目標函數所需要的格式。 設計模式 單例模式 JS的單例模式有別于傳統面向對象語言的單例模式,js作為一門無類的語言。使用全局變量的模式來實現單例模式思想。js里面的單例又分為普通單例和惰性單例,惰性單例指的是只有這個實例...

    Panda 評論0 收藏0
  • Effective JavaScript讀書筆記(一)

    摘要:如果為假值,不傳或者傳入,函數都會返回但是,傳入這個值是完全有可能的,所以這種判斷形勢是不正確的或者使用來判斷也可以原始類型優于封裝類型對象擁有六個原始值基本類型布爾值,數字,字符串,,和對象。 作為一個前端新人,多讀書讀好書,夯實基礎是十分重要的,正如蓋樓房一樣,底層穩固了,才能越壘越高。從開始學習到現在,基礎的讀了紅寶書《JavaScript高級程序設計》,犀牛書《JavaScri...

    zhoutao 評論0 收藏0
  • javascript高級程序設計》第六章 讀書筆記javascript繼承6種方法

    摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...

    孫吉亮 評論0 收藏0
  • JavaScript 設計模式讀書筆記(六)——門面模式

    摘要:簡單的門面模式實例事件綁定函數門面模式的作用是將復雜的接口進行包裝,變成一個便于使用的接口。還是以事件相關為例,事件綁定中還有兩個常用的分別是和。 門面模式是什么,與其我去用笨拙的語言去解釋,不如看下面這張圖,曾經在網上很火的一張圖片,說的是一位兒子為他的爸媽設置的電腦桌面。 showImg(http://segmentfault.com/img/bVcgHm); 有了這些起好名字...

    pubdreamcc 評論0 收藏0
  • JavaScript模式讀書筆記()字面量和構造函數

    摘要:對象字面量定義一個空對象這里的空指的是其自身屬性為空,對象繼承了的屬性和方法添加屬性方法完全刪除屬性方法自定義構造函數用操作符調用構造函數時,函數內部會發發生以下情況創建一個新對象,并且引用了該對象并繼承了該函數的原型屬性和方法被加入到的引 對象字面量 //定義一個空對象,這里的空指的是其自身屬性為空,dog對象繼承了Object.prototype的屬性和方法 var dog={} ...

    _Zhao 評論0 收藏0

發表評論

0條評論

lentrue

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<