標籤:prot nbsp 時間 模組 優勢 turn 利用 對象 oop
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設計模式:一、物件導向編程