2025-02-10

 

 

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遊戲上,效率還是很可觀的。

 

摘自 尋雨的學習空間

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *