夯實基礎,徹底掌握js的核心技術(二):面向對象編程(Object Oriented Programming)

單例設計模式(Singleton Pattern)

1. 單例模式解決的問題:

表現形式:

Var obj = {
xxx; xxx,
…
}

2. 作用:

把描述同一件事物的屬性和特徵進行“分組、分類”(存儲在同一個推內存空間中),因此避免了全局變量之間的衝突和污染

var pattern1 = {name: ‘xxx’}
var pattern2 = { name: ‘xxx’}
//name值並不是一個值,屬於兩個堆內存空間中

在單例設計模型中,obj不僅僅是對象名,它被稱爲”命名空間[NameSpace]”,<br />把描述事務的屬性存放到命名空間中,多個命名空間是獨立分開的,互不衝突

3. 單例設計模式命名的由來

每一個命名空間都是js中Object這個內置基類的實例,而實例之間是相互對立不干擾的,所以我們稱它爲“單例”:單獨的實例

4. 高級單例模式

  1. 在給命名空間賦值的時候,不是直接賦值一個對象,而是先執行匿名函數,形成一個私有作用域AA(不銷燬的棧內存),在AA中創建以愛國堆內存,把內存地址賦值給命名空間
  2. 這種模式的好處:我們完全可以在AA中創造很多內容(變量或者函數),哪些需要供外面的調取使用的,我們暴露到返回的對象中(模塊化實現的一種思想)

如下圖例子:

var nameSpace = (function () {
    var n = 12
    function fn () {}
    return {
    fn: fn
    }
})

this:

  1. 給當前元素的某個事件綁定方法,當事件觸發方法執行的時候,方法中的this是當前元素操作的元素對象
  2. 普通函數執行,函數中的this取決於執行的主體,誰執行的,this就是誰(執行主體:方法執行,看方法名前面是否有“點”,有的話,點前面是誰this就是誰,沒有this是window)
function fn () {
    console.log(1)
}
var obj = {fn:fn}

// 執行的是相同的方法,但是this指向不同
obj.fn(); // this=> obj
fn(); // this指向window

// 自執行函數,方法的this指向window
~function() {
 // this => window
} () 

var n = 2;
var obj = {
    n: 3,
    fn:(function (n) {
        n *= 2;
      this.n += 2;
      var n = 5;
      return function(m) {
        this.n *= 2;
      console.log(m + (++n))
      }
      //自執行函數執行的時候,堆內存還沒有存儲完成鍵值對,和obj還沒有關係,此時obj=undefined,obj.n會報錯
    })(n) 
}
var fn = obj.fn
fn(3) // 9
obj.fn(3) // 10
console.log(n, obj.n) // 8 6

解析如下圖:<br />

<br />

5. 基於單例的模塊化開發

  1. 團隊協助開發的時候,會把產品按照功能板塊進行劃分,每個功能板塊都有專人負責開發
  2. 把各個版塊之間公用的部分進行提取封裝,後期在想實現這些功能,直接的調取即可

工廠模式(Factory Pattern)

工廠模式(Factory Pattern)

  1. 把實現相同功能的代碼進行‘封裝’,以此來實現‘批量生產’(後期想要實現這個功能,我們只需執行函數即可)
  2. ‘低耦合高內聚’:減少頁面中的冗餘代碼,提高代碼的重複使用率
function createPerson (name, age) {
    var obj = {}
  obj.name = name;
  obj.age = age;
  return obj
}
var p1 = createPerson('xxx', 25)
var p2 = createPerson('xxx', 25)
console.log()

擁抱面向對象

面向對象編程,我們需要掌握“對象、類、實例”的概念<br />對象:萬物皆對象<br />類: 對象的具體細分(按照功能特點進行分類:大類、小類)<br />實例:類中具體的一個事物(拿出類別中的具體一個實例進行研究,那麼當前類別下的其他實例也具備這些特點和特徵)<br />js中內置類<br />object 對象類 (基類)

  1. Number數字類 String Boolean Null Undefined Array RegExp Function Date ...

  2. HTMLCollection 每一個元素集合都是它的實例

  3. NodeList

  4. EventTarget

    Node: Element:HTMLBodyElement HTMLDivElement<br />       WindowProperties: Window: window對象就是它的實例
    
  5. 基於基類,我們可以創建很多自己的類(自定義類)

結構如下圖:<br />

構造函數(constructor)

1. 基於構造函數創建自定義類(constructor)

  1. 在普通函數執行的基礎上“new xxx()”,這樣就不是普通函數執行了,而是構造函數執行,當前函數名稱稱之“類名”,接收返回的函數結果是當前類的一個實例
  2. 自己創建的類名,最好第一個單詞首字母大寫
  3. 這種構造函數設計模式執行,主要用於組件、類庫、插件、框架等的封裝,平時編寫業務邏輯一般不用這樣處理
function Fn() {}
var f1 = new Fn()  //Fn是類 f1是類的一個實例
var f2 = new Fn()   // f2也是Fn的一個實例
// f1和f2是獨立的,互不影響

2. JS中創建值有兩種方式:

  1. 字面量方式
var obj = {}
  1. 構造函數模式
var obj = new Object()

不管哪一種方式創造出來的都是Object類的實例,而實例之間是獨立分開的,所以var xxx = {} 這種模式也是js中的單例模式.

3. 基本數據類型基於兩種不同的模式創建出來的值是不一樣的

  • 基於字面量方式創建出來的值是基本類型值
  • 基於構造函數創建出來的值是引用類型
var num1 = 12; // 數字類Number實例,數字類的特殊表達方式之一
var num2 = new Number(12); // 數字類的實例
console.log(typeof num1) // "number"
console.log(typeof num2)  // "object"

4. 構造函數運行機制

<br />普通函數執行:

  1. 形成一個私有的作用域
  2. 行參賦值
  3. 變量提升
  4. 代碼執行
  5. 棧內存釋放問題

普通函數執行流程如下圖:<br />

<br />
<br />構造函數執行:<br />既有普通函數執行的一面,也有構造函數執行的一面

function Fn(name, age) {
    var n = 10;
  this.name = name;
  this.age = age + n;
}
var f1 = new Fn('xxx', 20);
var f2 = new Fn('aaa', 30)
console.log(f1=== f2); // false:兩個不同的實例(兩個不同的堆內存地址)
console.log(f1.age)  //30
console.log(f2.name) // 'aaa'
console.log('name' in f1) // true name和age在兩個不同的實例都有存儲,但是都是每個實例自己的私有屬性
console.log(f1.n) // undefined 只有this.xxx =xxx 的才和實例有關係,n是私有作用域的一個私有變量而已

  1. 像普通函數執行一樣,形成一個私有作用域(棧內存)

行參賦值、變量提升,都是私有變量

  1. 【構造函數獨有操作】在js代碼自上而下執行之前,首先在當前形成的私有棧中創建一個對象(創建一個堆內存:暫時不存儲任何東西),並且讓函數中的執行主體(this)指向這個新的堆內存(this === 創建的對象)
  2. 代碼開始自上而下執行
  3. 【構造函數執行獨有】代碼執行完成,把之前創建的堆內存地址返回(瀏覽器默認返回)

<br />

5. 構造函數中的一些細節問題

  1. 構造函數執行,不寫return ,瀏覽器會默認返回創建的實例,如果自己寫了return
  • return 是一個基本值,返回的結果依然是類的實例
  • 直接return是結束代碼執行,不會覆蓋實例
  • 如果返回的是引用值,則會把默認值返回的實例覆蓋,此時接收到結果就不再是當前類的實例了

所以構造函數執行的時候,儘量減少return使用,防止覆蓋實例<br />**

  1. 在構造函數執行的時候,如果不需要傳遞實參數,我們可以省略小括號,還是創建實例(和加小括號是沒有區別的)
  2. instanceof: 檢測某一個實例是否隸屬於這個類
  3. in:檢測當前對象是否存在某個屬性(不管當前這個屬性是對象的私有屬性還是公有屬性,只要有結果就是true)
  4. hasOwnProperty: 檢測當前屬性是否爲對象的私有屬性(不僅要有這個屬性,而且必須還是私有的纔可以)

原型鏈設計模式(prototype & proto

1. 原型鏈機制

原型(prototype)、原型鏈(proto)<br />[函數]<br />普通函數、類(所有的類:內置類、自己創建的類)<br />[對象]<br />普通對象、數組、正則、Math<br />實例是對象類型的(除了基本類型的字面量創建的值)<br />prototype的值也是對象類型的<br />函數也是對象類型<br />...

  1. 所有的函數數據類型都是天生自帶一個屬性:prototype(原型),這個屬性的值是一個對象,瀏覽器會默認給它開闢一個堆內存
  2. 在瀏覽器給prototype開闢的堆內存中,有一個天生自帶的屬性:constructor,這個屬性存儲的值是當前函數本身
  3. 每一個對象都有一個proto的屬性,這個屬性指向當前實例所屬類的prototype


原型鏈:
它是一種基於proto向上查找的機制。當我們操作實例的某個屬性或者方法的時候,首先找自己空間中私有屬性或者方法

  • 找到了,則結束查找,使用自己私有的即可
  • 沒有找到,則基於proto找所屬類的prototype,如果沒找到,基於原型上的proto繼續,向上查找,一直找到Object.prototype的原型爲止,如果再沒有,操作的屬性或者方法不存在
function Fn() {
    var n = 10;
  this.AA = function () {
    console.log('AA')
  }
  this.BB = function () {
    console.log('BB')
  }
}
Fn.prototype.AA = function () {
    console.log('AA[公]')
};
var f1 = new Fn;
var f2 = new Fn

解析如下圖:<br />

總結:

本篇文章主要分享了面向對象的一些知識,如果想了解更多,請掃下面二維碼,關注公衆號<br />
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章