javascript面向對象編程

---->什麼是類和對象
    這是所有面向對象編程之前必須弄明白的.
    所謂類:簡單地說就是模板,說的專業一些,是一類具有某種性質的物的集合.比如:人就是一個類,車也是一個類,等等.
    所謂對象:就是類的具體實現.如上面所說,人是一個類,一個具體的人就是一個對象,比如張三.
   
    對象是類的實例化後的結果.javascript中使用new關鍵字來實例化一個類,生成一個對象.
    例子:
        function people(){    //javascript中一個function也是一個類,這裏我們建立一個空的類people
        }
       
        var zhangsan=new people;    //實例化生成一個對象張三

---->一個具體形象的例子
    /*-->最簡單的類:
     *people類
     *    屬性:性別,年齡,姓名
     *    方法:說話
     */
        function people(name,sex,age){
            this.name=name;
            this.sex=sex;
            this.age=age;
            this.say=function(){
                return "我叫"+this.name;
            }
        }
       
        使用時:
        var zhangsan=new people;
        alert(zhangsan.say());
        var lisi=new people;
        alert(lizi.say());
        說明:
            上面使用了this關鍵字,this總是指向當前的對象,在上面例子中,zhangsan.say中具有this.name,這裏的this是當前的對象zhangsan.後面lisi.say則是指向當前對象lisi
            對象具有屬性,上面的name,sex和age就是對象的屬性.我們這樣可以訪問,如lisi.name,zhangsan.age
            對象還具有方法,比如上面的say.方法是通過構造函數實現的.使用時,如上面,用lisi.say(),zhangsan.say()
           
            當然我們還可以在實例化對象後爲對象添加新的屬性和方法.比如:
            zhangsan.girlfriend="小麗";
            zhangsan.doing=function(){
                return "I am eating";
            }

---->javascript類/對象和其他面嚮對象語言的異同
    相同點:面向對象編程的思想都是一樣的,世界上所有的具體事物都可以看成對象,而這些事物從屬的集合都可以看成類.我們要做的是構造我們需要的類,在實例化成我們需要的對象爲我們工作.
    不同點:其他面向對象編程的語言對於類/對象關心下面的事情:
            1.作用域:公用,私用,受保護,靜態.而javascript只有一種作用域:公用作用域.
            2.特性:繼承,多態.javascript不支持多態,繼承方面的內容將在"javascript對象的繼承"一文中介紹

---->構建javascript類/對象的方式
    首先,可以大致定義出下面幾種類型:
        1.工廠方式
        2.構造函數方式
        3.原型方式
        4.混合的構造函數/原型方式
        5.動態原型方法
        6.混合工廠方式
   
    具體說明:
        A.工廠方式:
            所謂工廠方式,是指先建立對象,然後再往對象裏面添加屬性和方法.
            eg.1
                var zhangsan=new Object;    //創建對象
                zhangsan.name="張三";        //給對象添加屬性
                zhangsan.say=function(){    //給對象增加方法
                    alert("我叫張三");
                }
            eg.2 上面的例子沒有封裝性,我們可以使用函數封裝,實現多重利用
                function people(){
                    var p_object=new Object;
                    p_object.name="張三";
                    p_object.say=function(){
                        alert("我叫張三");
                    }
                    return p_object;    //返回對象
                }
                var zhangsan=people;
                var lisi=people;
                上面zhangsan和lisi兩個對象具有完全相同的屬性和方法,都叫"張三"(name屬性),都會說"我叫張三"(say()方法)
            eg.3 通過傳遞參數改進eg.2
                function people(name){
                    var p_object=new Object;
                    p_object.name=name;
                    p_object.say=function(){
                        alert("我叫"+this.name);
                    }
                    return p_object;    //返回對象
                }
                var zhangsan=people("張三");
                var lisi=people("李四");
            總結:
                工廠方式,總是先創建一個對象,再往對象中添加你需要的屬性和方法.但這種做法對於封裝性和多種利用性不是很有利,這導致了這種對象的構造方法不被提倡.
                使用工廠方式總是爲每個對象創建獨立的函數版本.
                這類方式使用封裝然後調用新對象的時候不使用new創建對象.
               
        B.構造函數方式:
            所謂構造函數方式,就像我給出的例子"一個具體形象的例子",就是採用構造函數的方式.它和工廠方式的區別是不再在函數內部創建一個對象.而是通過this關鍵字指向當前對象.
            構造函數的例子不再給出.
            構造函數和工廠方式一樣,會重複生成函數,爲每個版本的對象創建獨立的函數版本.
       
        C.原型方式
            所謂原型方式,就是利用prototype屬性來實現屬性和方法的繼承
            eg.1
                function people(){
                }
               
                people.prototype.name="張三";
                people.prototype.say=function(){
                    alert("我叫"+this.name);
                };
               
                var zhangsan=new people();
                var lisi=new people();
            原型方式不能通過構造函數傳遞參數初始化屬性的值,因爲所有的屬性和方法都是通過prototype添加的
           
        D.混合的構造函數/原型方式
            對於對象的屬性,使用構造函數的方式
            對於對象的方法,使用原型方式
            eg.1
                function people(name){
                    this.name=name;
                }
                people.prototype.say=function(){
                    return "我的名字叫"+this.name;
                };
               
                var zhangsan=new people("張三");
                document.write(zhangsan.say());
           
            eg.2 我們也可以把prototype寫入類,實現視覺上的封裝.
                function people(name){
                    this.name=name;
                    people.prototype.say=function(){
                        return "我的名字叫"+this.name;
                    };
                }
               
                var zhangsan=new people("張三");
                document.write(zhangsan.say());
           
            總結:這種構造類/對象的方法是推薦使用的
           
        E.動態原型方式
            這是在混合的構造函數/原型方式上改進的一種方式(提供更友好的編碼風格),他們功能是等價的
            eg.1
                function people(name){
                    this.name=name;
                    if(typeof people._initialized=="undefined"){
                        people.prototype.say=function(){
                            return "我的名字叫"+this.name;
                        };
                        people._initialized=true;
                    }
                }
                var zhangsan=new people("張三");
                document.write(zhangsan.say());
                var lisi=new people("李四");
                document.write(lisi.say());
            這樣處理的目的是創建對象的方法後下一次使用時不要再創建.
            由於上面的原因,動態原型方式也是javascript中常用的一種創建類/對象的一種方式
           
        F.混合工廠方式
            混合工廠方式幾乎和工廠方式是一樣的.它同樣是先構造對象,然後再往對象中添加屬性和方法.不同的是,混合工廠方式生成對象時依舊使用new關鍵字.
            eg.1
                function people(){
                    var p_object=new Object;
                    p_object.name="張三";
                    p_object.say=function(){
                        alert("我叫張三");
                    }
                    return p_object;    //返回對象
                }
                var zhangsan=new people;
                var lisi=new people;
                zhangsan.say();
                lisi.say();
            混合工廠方式和工廠方式以及經典方式(構造函數,原型方式)一樣會產生問題,不推薦使用
           
    對各種構建類/對象方式的總結:
        通常地,我們使用混合的構造函數/原型方式,即屬性使用構造函數方式,方法採用原型方式.當然,加強地,我們可以使用動態原型方式.
        上面兩種方式是推薦使用的.
       
                   
---->關於prototype的其他功能
    1.給對象(包括本地對象)添加新的方法
        比如Array對象,你可能需要添加一個方法toHexString,你可以這樣做:
            Array.prototype.toHexString=function(){
                //code here
            }
    2.重定義方法
        實質是讓方法指向一個新的函數
            Array.prototype.toHexString=function(){
                //other code href
            } 

對象繼承
 繼承,通俗地說,之前你寫過一些類,這些類中有一些是而你現在要寫的類的功能的子集或者基本相同,那麼你不用完全重新寫一個新的類,你可以把之前寫的類拿過來使用.這樣的一種代碼重用過程就叫做繼承.
    深入學習javascript繼承之前,先了解下面的幾個概念:
        父類:被繼承的類
        子類:由繼承得來的類
        超類:也就是父類
        抽象類:一般不用來實例化的類,它的用途是用來給其他類繼承.
        基類:提供給其他類可以繼承的類
        派生類:由基類繼承而來的類

    javascript對象繼承通常有下面的5種方式:
        1.對象冒充
        2.call()方式
        3.apply()方式
        4.原型鏈
        5.混合方式
   
    A.對象冒充
        所謂對象冒充,就是新的類冒充舊的類(舊的類必須採用構造函數方式),從而達到繼承目的.
        eg.1
            function people(name,sex,age){    //使用構造函數方式
                this.name=name;
                this.sex=sex;
                this.age=age;
                this.say=function(){
                    alert("My name is "+this.name);
                };
                this.doing=function(){
                    alert("I am speaking");
                };
            }
            var Marry=new people("Marry","Woman","23");
            Marry.say();
            Marry.doing();
           
            function white_people(name,sex,age){
                this.inherit=people;
                this.inherit(name,sex,age);
                delete this.inherit;
               
                this.area=function(){
                    alert("I am in Europe");
                }
            }
            var Tom=new white_people("Tom","man","21");
            Tom.say();
            Tom.area();
            alert(Tom.age);
        上面的例子中,people是用來做white_people的基類,記住這個格式是用來對象冒充達到繼承目的的
                this.inherit=people;            //冒充
                this.inherit(name,sex,age);        //繼承
                delete this.inherit;            //刪除繼承
        所有新屬性和新方法都必須再刪除了繼承後定義,這樣是爲了避免覆蓋父類的相關屬性和方法.
        另外,對象冒充支持多繼承.
        eg.2
            function worker(pay,work){
                this.pay=pay;
                this.work=work;
            }
            function city_worker(name,sex,age,pay,work){
                this.inherit=people;
                this.inherit(name,sex,age);
                delete this.inherit;
               
                this.inherit=worker;
                this.inherit(pay,work);
                delete this.inherit;
            }
           
            var Jerry=new city_worker("Jerry","man","21","$1000","coder");
            Jerry.say();
            alert(Jerry.work);
        對象冒充有一個不足的地方:多繼承機制實現時,如果基類存在相同的屬性或者方法,將從後面的類繼承.
       
    B.call()方式
        只是封裝的對象冒充的一個函數.這樣,我們不再需要寫"經典"的三句話,而是用下面這句話代替:
            基類.call(對象,參數列表)
        eg.1
            function farmer(name,sex,age,pay,work){
                people.call(this,name,sex,age);
                worker.call(this,pay,work);
            }
           
            var Nicholas=new farmer("Nicholas","man","27","$3000","irrigator");
            Nicholas.say();
            alert(Nicholas.pay);
        同樣,call()存在同名屬性和方法的小問題.
       
    C.apply()方式
        和call()一樣.apply()也是對象冒充的一個封裝函數.其格式爲:
            基類.apply(對象,參數數組);
        eg.1
            function white_collar(name,sex,age,pay,work){
                people.apply(this,new Array(name,sex,age));
                worker.apply(this,[pay,work]);
            }
           
            var Jiessie=new white_collar("Jiessie","woman","26","$2500","editor");
            Jiessie.say();
            alert(Jiessie.work);
        同樣,apply()存在同名屬性和方法的小問題.
       
    D.原型鏈
        上面三種方式都是採用構造函數方式的繼承,對應地,也具有原型函數方式的繼承:原型鏈.
        eg.1
            function blue_collar(){
            }
            blue_collar.prototype.name="Jean";
            blue_collar.prototype.age="33";
            blue_collar.prototype.say=function(){
                alert("my name is "+ this.name);
            };
           
            function city_blue_collar(){
            }
            city_blue_collar.prototype=new blue_collar();
           
            var jj=new city_blue_collar;
            jj.say();
        原型鏈也具有了原型鏈的缺點:不能傳遞參數.另外,原型鏈不支持多繼承,因爲
       
    E.混合方式
        使用構造函數方式來寫類的屬性,對屬性的繼承採用call()或者apply()
        使用原型方式來寫的方法,對方法的繼承採用原型鏈
        eg.1
            function beauty(name,age){
                this.name=name;
                this.age=age;
            }
            beauty.prototype.say=function(){
                alert("小女叫"+this.name);
            };
           
            function china_beauty(name,age,area){
                beauty.call(this,name,age);
                this.area=area;
            }
            china_beauty.prototype=new beauty();
            china_beauty.prototype.from=function(){
                alert("我來自"+this.area);
            };
           
            var diaochan=new china_beauty("貂禪","16","臨洮");
            diaochan.say();
            diaochan.from();
            alert(diaochan.age);

對象編程規範(個人)

    前面兩篇介紹了javascript對象編程的基礎以及對象的繼承.
    在基礎篇我們知道如何創建對象,並通過對象編程.當然,我們還必須知道各種創建對象的方法以及他們之間的利弊.
    在對象繼承篇我們知道了如何利用對象的繼承性質提高代碼的可重用性,以及如何根據創建對象方式選擇對應的繼承方式.
   
    對於多種創建類/對象的方式,以及對應的創建繼承方式,有必要根據自己的習慣,以及更好的編碼習慣來規定一種規範.下面是針對自己的javascript創建類/對象的規範.
   
    1.如何創建類/對象
        使用"混合構造函數/原型方式"
    2.怎麼繼承
        對應創建,採用"混合方式"進行繼承
   
    採用之前寫的一個例子.
        function beauty(name,age){    //基類:美女,這裏採用構造函數方式,接收參數,設置類的屬性
            this.name=name;            //美女的名字
            this.age=age;            //美女的年齡
        }
        beauty.prototype.say=function(){    //基類:爲美女添加方法,採用原型方式
            alert("小女叫"+this.name);
        };
           
        function china_beauty(name,age,area){    //派生類:中國美女
            beauty.call(this,name,age);            //繼承美女的屬性
            this.area=area;                        //添加自己的屬性:來源地
        }
        china_beauty.prototype=new beauty();    //繼承美女的方法
        china_beauty.prototype.from=function(){    //添加自己的方法:介紹來源地
            alert("我來自"+this.area);
        };
           
        var diaochan=new china_beauty("貂禪","16","臨洮");    //創建中國美女對象"貂禪"
        diaochan.say();            //使用繼承自美女類的方法say
        diaochan.from();        //使用自己的方法from
        alert(diaochan.age);    //使用繼承自美女的屬性age

發佈了20 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章