由於JavaScript的靈活性,可以讓每個人按照自己的習慣進行編寫代碼.有函數式的編程方式,也有現在用的較為廣泛的對象字面量.由於面向對象的出現,JavaScript剛開始的函數編程也逐漸演化為類式程式設計方式.現在我對幾種比較熟悉的程式設計習慣做簡單的說明:
1.對象字面量:
以下為引用的內容: var person = { name:null, setName:function(name){ this.name = name; return this.name; }, getName:function(){ alert(this.name); } } |
具有JavaScript特色的一種程式設計方式,以類別為單位含有屬性name,方法setName和getName.呼叫方法比較簡單person.setname('R'),this由此至終均指向person,person的屬性與方法均不私有,可以進行呼叫.
2.prototype構造器呼叫模式
以下為引用的內容: var Person = function(){ this.name = null; } Person.prototype.setName = function(name){ this.name = name; } Person.prototype.getName = function(){ alert(this.name); } |
也是很常見的程式設計方式,建立一個Person類別,然後利用prototype對類別進行擴充,新增方法.與物件字面量最大差別在於,呼叫該類別的方法時,必須先new(跟Java呼叫類別相似).var p = new Person();p.getName();如果不用new,而直接創建,會產生錯誤.而且這種錯誤將不會報錯,難以發現.錯誤的產生原因來自於this指向Person.prototypel,而Person並沒有setName方法.
3.利用匿名函數進行函數編程
以下為引用的內容: (function(){ var name;
var setName = function(n){ name = n; } window['person']['setName'] = setName;
var getName = function(){ alert(name); } window['person']['getName'] = getName; })() |
類別的出現,其中一個最大的好處就是降低了全局變數的出現,但是如果你依舊習慣於函數式編程,沒關係,只要創建一個匿名函數,進行閉包,就可以再裡面進行函數編程,也不需要擔心全域變數的出現.如上所看到的var name;在匿名函數外部是無法調用的,然後利用外部的變數來調用內部的函數,或者是變數.可以藉此創建私有變數和私有方法.
4.類式程式設計(不知道取什麼名)
以下為引用的內容: var person = function(){ var name = null; return{ setName:function(n){ name = n; }, getName:function(){ alert(name); } } } |
與對象字面量很相似,其不同之處在於拋開了this,和可以對方法與屬性進行私有.調用方法與對象字面量基本一致.
5.方法鏈
以下為引用的內容: var Person = function(){ this.name = null; } Person.prototype = { setName:function(name){ this.name = name; return this; }, getName:function(){ alert(this.name); return this; } } |
jQuery就是一個最經典的方法連函式庫,如果還不懂方法鍊是什麼,看看這個例子:
以下為引用的內容: var p = new Person(); p.setName('Tom').getName().setName('Ray').getName(); |
由於每個方法的結尾都是return this;所以產生了方法鍊式的類別.
本人比較熟悉的就是這幾種方式了,每個人都有每個人的特色,所以方式也是說不盡的.但是藉此,我想探討以下幾個問題:
1.有關於this指針
在建立多種類的時候都用到this,可是this的作用究竟是什麼,而其實this在重用和繼承上起著很大的作用.我們先看看一個關於繼承的例子:
首先建立Person類別:
以下為引用的內容: var Person = function(){ this.name = null; } Person.prototype.setName = function(name){ this.name = name; } Person.prototype.getName = function(){ alert(this.name); } Person.prototype.getAge = function(){ var age = this.age || ''; alert(age); } |
然後在建立一個Children類別,並整合Person的所有方法和屬性:
以下為引用的內容: var Children = function(age){ this.name = null; this.age = age; } Children.prototype = new Person(); //繼承Person的屬性與方法 Children.prototype.ageJudge = function(){ //另外為Children新增方法 if(this.age > 18){ alert('成年人~'); } else { alert('未滿18歲呢~'); } } Children.prototype.getName = function(){ //重寫getName方法 var about = this.name + ' ' + this.age; alert(about); } var tom = new Children(12); var ages = tom.getAge(); //12 var judge = tom.ageJudge(); //未滿18歲呢~ var setN = tom.setName('Tom'); var get = tom.getName(); //Tom 12 |
這就是繼承,然後我們看個簡單的函數重用:
以下為引用的內容: var SetColor = function(){ this.style.backgroundColor = '#000'; //this指向window } document.body.onclick = SetColor; //此時this指向body documnet.getElementById('color').onmouseout = SetColor; //this指向documnet.getElementById('color') 看了this的作用之後,想必對this有了新的認識了吧.現在就有疑問了,就是this的該用與不該用,下面在看個簡單的例子: var setColor = { init:function(obj){ this.obj = obj; //this指向setColor this.obj.onclick = this.color; }, color:function(){ this.style.backgroundColor = '#000'; //this指向obj } } |
就在一個類別裡,this卻指向2處地方,有時這樣總會讓人覺得困惑.剛學習的人更會被this弄的暈頭轉向.而稍稍改變一下寫代碼的方式:
以下為引用的內容: var setColor = { init:function(obj){ setColor.obj = obj; setColor.obj.onclick = setColor.color; }, color:function(){ this.style.backgroundColor = '#000'; //this可以方便方法的重複使用 } } |
這樣一下來,程式碼可以更加的清晰了.所以編寫程式碼的時候應該考慮好究竟今後的用途,還有能否重用.如果明確了不進行繼承或是重用,個人覺得應該盡可能的避免使用this,更有個比較常出現的問題.如下:
以下為引用的內容: var Person = function(){ this.name = null; } Person.prototype.setName = function(name){ this.name = name; } Person.setName('tom'); //錯誤方式此時setName方法中的this會指向Person.prototypel,Person並沒有setName方法 |
前面講過,若果不寫成var p = new Person();p.setName('tom');該類別裡的this將會直接指向Person.prototypel.這種錯誤在編譯時,還是運行時都不會報錯.有時會造成讓人很頭痛的問題.所以在編寫程式碼時,我總是很慎重的選用this.
2.類的封裝
在Java裡,對類別的方法或是屬性,可以設定為私有,這樣就可以避免外部的呼叫,而JavaScript卻不存在這樣的設定,看看下面的程式碼:
以下為引用的內容: var person = { name:null, init:function(name){ this.setName(name); }, setName:function(name){ this.name = name; return this.name; } } person.init('tom'); //tom |
在這個類別裡,一共有2個方法,分別是init和setName,而我們只希望從init中運行setName,或是以後將會為裡面添加的各種方法,而不希望出現:
person.setName('tom'); //tom
直接呼叫setName方法,正確的說,希望setName方法私有,還有name屬性私有.避免別的程式設計師使用你的類別時,呼叫了不想被呼叫的方法.
那該怎麼對類別的封裝好呢?試試另一種程式設計方式吧,看看改版的怎麼樣:
以下為引用的內容: var person = function(){ var name = null; var setName = function(n){ name = n; return name; } return{ init:function(n){ setName(n); } } } |
這樣子,就可以講原本要私有化的方法和屬性私有化了,外部無法直接調用了.這也是利用了閉包而達成所需要的方式的.可是這種編程方式不易於讀,尤其是新手看到這種程式碼會很吃力,還有在佔用記憶體方面也要比一般的高些.
好了,暫時先介紹到這裡,下次有時間在說說閉包與作用域.