JavaScript設計模式:一、面向對象編程(第二節)
一、封裝
面向對象編程思想其中的一個特點就是封裝,通俗的講法就是把需要的功能方向在一個對象裏。遺憾的是,對於JS這種解釋性的弱類型語言沒有經典強類型語言中那樣通過class等關鍵字實現類的封裝方法,js中都是通過一些特性模仿實現的,雖然這是個弊端,但也帶來了極高的靈活性。
我們看一個Book類是如何通過JS實現的:
1 // 寫法1 2 var Book = function (id, name, pirce) { 3 this.id = id 4 this.name = name 5 this.price = pirce 6 } 7 8 /* 9 * 以下兩種方式不可混用10 */ 11 12 // 也可以通過在類的原型對象prototype上添加屬性和方法,有兩種方式 13 // 一種是一一為原型對象屬性賦值 14 Book.prototype.display = function () { 15 // ... 16 } 17 18 // 一種是將一個對象賦值給類的原型對象 19 Book.prototype = { 20 display: function () { 21 // ... 22 } 23 }
這樣,我們就將所需要的方法和屬性都封裝在我們抽象的Book類裏面,當使用功能方法時,我們不能直接使用Book類,需要用new關鍵字來實例化新的對象,並通過點語法來訪問對象的屬性或者方法。比如:
1 var book = new Book(10, ‘書‘, ‘50‘) 2 console.log(book.name) // 書
從代碼可以看出,我們通過this添加了屬性,通過prototype添加了方法,那麽這兩者有什麽區別?
通過this添加的屬性和方法是在當前對象上添加的,然而JS是一種基於原型的prototype的語言,所以每次創建一個新對象時,通過prototype繼承的方法並不是對象自身的,所以在使用這些方法時,需要通過prototype一級一級查找的來,而通過this定義的屬性或者方法是該對象自身所擁有的,所以我們每次創建一個新對象時,this指向的屬性和方法都會得到相應的創建。
二、屬性與方法封裝
在OOP中,既然是類,必定有私有屬性,私有方法,共有屬性,共有方法等這些概念,那麽JS中又是如何去實現呢?
由於JS的函數作用於,聲明在函數內部的變量以及方法在外界是訪問不到的,通過次特性可以創建類的私有變量以及私有方法,然而在函數內部通過this創建的屬性和方法,在類創建對象時,每個對象自身都擁有一份並且可以在外部訪問到,因此這些屬性和方法可以看作為共有的,還是Book為例:
1 // 私有屬性與私有方法,特權方法,對象共有屬性和對象公有方法 2 var Book = function (id, name, price) { 3 // 私有屬性 4 var num = 1 5 // 私有方法 6 function checkId () { 7 // ... 8 } 9 // 特權方法 10 // 所謂的特權方法,是既可以被外部訪問到,又可以訪問類內部的私有屬性與方法的方法 11 this.getName = function () { 12 // ... 13 } 14 this.getPrice = function () { 15 // ... 16 } 17 this.setName = function () { 18 // ... 19 } 20 this.setPrice = function () { 21 // ... 22 } 23 // 對象公有屬性 24 this.id = id 25 // 對象公有方法 26 this.copy = function () { 27 // ... 28 } 29 30 }
而在OOP中,還有兩個概念是:靜態屬性與靜態方法,這兩種東西都屬於類所有,而不屬於每一個對象,調用也只能通過類名加上點語法來使用,那麽JS中如何實現呢?
其實很簡單,我們可以在類定義的外面,通過點語法定義屬性以及方法,這樣,通過new關鍵字創建時,這寫在類外面通過點語法添加的屬性和方法是不會被執行到的,因而只能被類本身所調用,我們也就達到了模仿靜態屬性與方法的目的。
1 // 類靜態公有屬性(對象不能訪問) 2 Book.isChinese = true 3 // 類靜態公有方法(對象不能訪問) 4 Book.getIsChinese = function () { 5 return Book.isChinese 6 }
JavaScript設計模式:一、面向對象編程(第二節)