淺談Javascript物件導向程式設計

舟之橋發表於2013-03-13

轉載地址:http://www.2cto.com/kf/201111/111212.html


Javascript是一門很靈活的語言,允許我們模擬物件導向程式設計中的很多機機制。在JS中充分使用物件導向設計思想,可以極大限度的提升程式碼重用、降低模組間的偶合、更好的邏輯分層與並行開發。下面分幾個步驟簡單談下我的理解。

 

一、資料型別與包裝類

 

包裝類 …… 型別名 …… 常見值 …… 分類

 

Number ……number ……123.123 …… 基本資料型別

 

Boolean ……Boolean ……true、false …… 基本資料型別

 

String ……string …… “hello world!” …… 基本資料型別

 

Object ……object ……{}、[] …… 複合資料型別

 

Function ……function ……function(){} …… 特殊型別

 

無 ……undefined ……undefined、未定義  …… 小資料型別

 

無 ……null ……null …… 小資料型別

 

         內建型別與本文關係不大,不列出。

 

二、引用型別與值型別

 

引用型別:object function

 

值型別:number、boolean、string、null、undefined

 

三、new function(構造器)與prototype(原型)

 

關於prototype的設計模式就不多說了,網上很多介紹,以一個例子介紹一下js中使用new構造物件的過程。

 

function classname(){this.id=0;}   var v=new classname();

 

當使用function構造物件時,進行以下流程:

 

1、 查詢classname的prototype,並進行淺拷貝。

 

2、  繫結this指標到拷貝來的物件。

 

3、  將this.constructor屬性設定為classname。

 

[注:其實classname.prototype.constructor的值也被設定為classname,第六部分會說明]

 

4、  執行使用者{}中的程式碼。

 

5、  返回this指標賦予左值v。

 

四、實現物件導向的三個基本特徵

 

1、 封裝

 

封裝這個大家都明白,在js中,重點在於訪問許可權。在其他原生支援面嚮物件語言中,一般支援public、protected、private三個關鍵字來控制訪問許可權,但在js中,我們只能依靠複雜的作用域關係來控制:

 

function classname(a){

 

        var uid=a; //uin為模擬private,作用域為{},外部無法使用

 

        this.getuid=function(){return a;} //為uid提供一個外部只讀介面obj.getuid();

 

        this.setuid=function(val){a=val} //為uid提供一個外部可寫介面obj.setuid(5);

 

this.id=uid; //id為模擬public   obj.id 使用

 

}

 

classname.prototype.func=function(){}; //模擬public方法obj.func()呼叫

 

classname.stafunc=function(){}; //模擬靜態方法classname.stafunc()呼叫

 

var obj=new classname(1);

 

[!]非常需要注意的就是,因為function是引用型別,classname.prototype.func是所有物件共享的一個function物件(每個物件僅存著引用),因此物件規模不大。而使用this.getuid和this.setuid為定義一個function,因此每個物件例項都會存一份,如果放肆使用這種方法,會造成物件規模龐大,影響效能。個人認為模擬private變數的意義不大。

 

[!]如果有需求真的需要大量使用this.xxx=function(){}這種情況,在function(){}中的this指標與最外的this指標是不同的,最好在類定義的首行加上var _this=this;,這樣在this.xxx=function(){}中也可以方便使用繫結的指標。

 

2、 繼承

 

繼承的實現,主要有2種方法:第一種是使用javascript本身的原型模型,通過給prototype賦值並改變其constructor屬性來實現繼承;第二種方法是不使用prototype,手動實現將父物件的所有屬性方法深拷貝到子物件。比如A需要繼承B,第一種寫法可以:A.prototype=new B();A.prototype.constructor=A; 第二種寫法可以寫一個遞迴,或者使用jquery中的方法extend。另外,如果要實現多繼承的話,prototype就真的好麻煩了(需要依次多個類,還要建空物件來接),第二種方法就比較簡單,依次拷貝即可。一般這種繼承為了找父類方便,可以在物件中加個屬性,引用父類。

 

3、 多型

 

函式過載就不說了,都會,檢查引數即可,很靈活。隱藏屬性就是直接賦值undefined。需要注意的是,如果是打算繼承B類的prototype,一定要建一個空物件來接,否則的話,你給類寫方法的話,相當於直接修改了prototype,就算不寫方法,你最後修改constructor時也會造成繼承鏈錯亂,接個空物件很容易:

 

function temp(){};

 

temp.prototype=B;

 

var obj=new temp();

 

這樣再讓需要繼承B.prototype的類繼承obj即可,即便修改prototype也不會影響到B。而且也不像繼承new B()那樣浪費很多空間。

 

五、深拷貝與淺拷貝

 

這個和其他語言中沒什麼區別,淺拷貝就是直接拷貝,遇到引用型別或類型別不再深入。深拷貝則是根據型別判斷,進行遞迴拷貝。

 

六、prototype.constructor

 

這個值主要是用於維護繼承的原型鏈。

 

七、JS的物件導向開發

 

由於我不是前臺開發人員,見過專案有限,僅談自己的經驗。

 

我開發過的B/S,常用兩種架構,一種是以CGI為主,由後臺語言去生成HTML,JS僅僅做一些使用者互動,ajax通訊等。另外一種是使用MVC,後臺語言僅僅生成JSON,View層完全由JS元件在客戶端實現。後者一般大量使用物件導向的思想進行程式設計,將元件封裝成類,將JSON傳入建構函式,再由控制器或佈局元件Add進來。由於元件可以重用,在開發後臺管理系統、JS遊戲上,效率還是很可觀的。


相關文章