JavaScript模擬Java類繼承

jopen 10年前發布 | 12K 次閱讀 JavaScript開發 JavaScript

    javascript采用原型繼承的方式繼承一個類,但一些使用過Java的程序員可能習慣使用經典的類繼承,但javascript原生并不支持這種方式,因此需要手動實現。我是通過定義一個定義類的函數實現的,由于javascript沒有訪問修飾符,因此如果需要使用到private成員,請使用閉包。

/將一個對象的自有屬性復制到另一個對象的方法/
        function merge(from, to){
            for(var i in from){
                if(from.hasOwnProperty(i)){
                    to[i] = from[i];
                }
            }
        }

    /*用于定義一個類
     *參數:構造函數,繼承的父類, 屬性, 靜態屬性, 是否為單例模式
     *注意:單例模式下返回非原始構造函數
     */
    function defineClass(constructor, parent, properties, statics, isSingleton){
        /*如果為單例模式,保存實例,并在以后的調用中返回此實例*/
        if(isSingleton){
            var instance, oldConstructor = constructor;
            constructor = function(){
                if(instance) return instance;
                oldConstructor.apply(this, arguments);
                instance = this;
            }
        }
       /*設置原型屬性,這意味著傳入的構造函數的原型屬性將被覆蓋
        *javascript沒有函數重載,因此parent函數需要做一些特殊處理,詳情見parent定義
        */
        constructor.prototype = new parent();
       /*將自有屬性復制到原型中
        *將靜態屬性復制到構造函數中,這意味著將不會繼承parent的靜態屬性
        */
        merge(properties, constructor.prototype);
        merge(statics, constructor);
       /*將構造函數更改為當前構造函數
        *將parent的引用保留
        */
        constructor.prototype.constructor = constructor;
        constructor.prototype.parent = parent;
        return constructor;
    }

    function parent(){
       /*可以將這里看成兩個構造函數,一個在定義子類時使用的無參構造函數,一個有參構造函數
        *如果子類需要參數來使用父類初始化,可以通過this.parent得到
        */
        this.name = "parent";
        if(arguments.length){
            log(this.name + "'s constructor with params");
        }
    }

    var child = defineClass(function(){
        //this.parent.apply(this, arguments);
        this.name = "child";
        if(arguments.length){
            log(this.name + "'s constructor with params");
        }
    }, parent, {
        say: function(){
            log(this.name);
        }
    }, {
        value: "static"
    }, true);

    var instance = new child(), instance2 = new child();

    log(child.value);                           //static
    log(instance.name);                        //child
    instance.say();                             //child
    log(instance === instance2);              //true
    log(instance instanceof parent)           //true

   /*可以在child基礎上擴展
    */

    var grandSon = defineClass(function(name){
        this.name = "grandSon";
        if(arguments.length){
            log(this.name + "'s constructor with params");
        }
    }, child, {
        shout: function(){
            log("shout: " + this.name);
        }
    });

    var instance3 = new grandSon();

    instance3.say();                           //grandSon
    instance3.shout();                         //shout: grandSon

    log(instance3 instanceof child);        //true
    log(instance3 instanceof parent);        //true

    /*打印日志*/
    function log(msg){
        if(window.console){
            console.log(msg);
        }
    }</pre>
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!