1. 程式人生 > >JavaScript設計模式:一、面向對象編程

JavaScript設計模式:一、面向對象編程

this 依賴 人在 turn obj log javascrip 體會 創建

JavaScript面向對象編程

眾所周知,JS作為一門腳本語言,由於其設計者在設計JS的時候,也僅僅用了很少的時間就完成了JS這門語言的創建,JS雖然擁有著腳本語言的優勢,但是JS也存在著天生的缺陷。其中之一就是:“沒有完整的面向對象和自定義類型支持”,這是因為JS本身沒有很好的模塊化。但事實上是,很多JS學習者或者使用者的共同點是:他們接觸的第一門編程語言大都是C++或者Java這種老牌OOP語言,寫代碼時都是秉持著面向對象的思想,這在學習JS或者使用JS不免會感到有一些難受。

那麽JS可不可以實現面向對象編程,或者說,在某種程度上做到面向對象編程?答案是肯定的。

一、用對象收編函數與變量

我們先看三個函數:

 1 function fn1 () {
 2   // ...
 3 }
 4 
 5 function fn2 () {
 6   // ...
 7 }
 8 
 9 function fn3 () {
10   // ...
11 }

這段代碼有一個問題就在於:定義了三個全局函數,在一個項目裏,這是不提倡的事實上也是不被允許的,創建全局函數或者變量,意味著在以後的代碼裏,這些函數或者變量就有與他人的代碼產生沖突的可能。那麽怎麽解決這一類的問題呢?

我們知道,對象可以擁有自己的屬性與方法,並且在我們需要使用這些屬性和方法的時候,通過點語法來使用。可不可以利用對象來收編這些函數或者變量呢? 看下面的代碼:

 1 var obj = {
 2   fn1: function () {
 3     // ...
 4   }
 5   fn2: function () {
 6     // ...
 7   }
 8   fn3: function () {
 9     // ...
10   }
11 }

通過創建一個這樣的對象,我們就可以通過obj.fn1的方式,來調用對應的方法,並且這些方法是存在於obj對象上的。

我們再看看下面的這種寫法(與上面的寫法其實是一種意思):

 1 var Obj = function () {}
 2 Obj.fn1 = function () {
 3
// ... 4 } 5 Obj.fn2 = function () { 6 // ... 7 } 8 Obj.fn3 = function () { 9 // ... 10 }

上面的方法存在著另外一個問題,當別人需要使用我們的對象方法的時候就有一些麻煩了,因為這個對象並不能被復制一份或者說我們通過 new 關鍵字

var test = new Obj() ,所創建的新對象test,並不擁有fn1,fn2,fn3這些方法。

要想解決這個問題,我們可以這麽寫:

 1 var Obj = function () {
 2   return {
 3     fn1: function () {
 4       // ...
 5     }
 6     fn2: function () {
 7       // ...
 8     }
 9     fn3:function () {
10       // ...
11     }
12   }
13 }

這樣寫有什麽作用呢?可以看出,每次調用該函數時,都會返回一個新對象,新對象擁有fn1,fn2,fn3這三個方法。這樣,每個人在使用時就互不影響了。

1 var test = Obj()
2 test.fn1()

我們雖然通過返回一個新對象在一定程度上解決了他人使用的問題,但這並不是真正意義上的類的創建方式(相信Java或者C++使用者深有體會),並且我們上面創建的對象test與Obj沒有任何的關系,所以,我們再次換一種寫法:

 1 var Obj = function () {
 2   this.fn1 = function () {
 3     // ...
 4   }
 5   this.fn1 = function () {
 6     // ...
 7   }
 8   this.fn1 = function () {
 9     // ...
10   }
11 }

我們在這個函數內,使用了this關鍵字,像上面這樣的一個對象Obj,我們就可以將其看成一個類了,擁有三個成員函數:fn1,fn2,fn3,既然是一個類,那麽使用的時候就要通過new關鍵字來創建對象了:

1 var test = new Obj()
2 test.fn1()

另一個問題出現了,每一個使用new關鍵字所創建出來的新對象,通擁有屬於自己的一套方法,但事實上,這並不是必要的,這會造成內存不必要的消耗。

怎麽解決這個問題呢?不知道讀者是否還記得JS中的每一個函數,都有一個prototype對象,我們稱之為“原型”,原型上的屬性和方法是new出來的對象所共享的,我們是否可以將公共的函數轉移到prototype上呢?

 1 var Obj = function () {}
 2 Obj.prototype.fn1 = function () {
 3   // ...
 4 }
 5 Obj.prototype.fn2 = function () {
 6   // ...
 7 }
 8 Obj.prototype.fn3 = function () {
 9   // ...
10 }

這樣我們以後通過new關鍵字創建的對象實例,所擁有的都是共同的方法,因為他們都要依賴prototype原型依次尋找,找到的方法都是同一個。

以上的這種方式,還有另一個寫法:

 1 var Obj = function () {}
 2 Obj.prototype = {
 3   fn1: function () {
 4     // ...
 5   }
 6   fn2: function () {
 7     // ...
 8   }
 9   fn3: function () {
10     // ...
11   }
12 }

需要註意的是,這兩中方式並不能混用,因為如果在後面為對象的原型對象賦值為新對象的時候,它會覆蓋掉之前對prototype對象賦值的寫法。

JavaScript設計模式:一、面向對象編程