Javascript OOP框架YOOP重構實踐(上)


大家好!今天跟大家一起分享我的OOP框架YOOP重構實踐,希望能與大家一起共同學習、共同進步。

本文展示了我對沒有編寫測試的YOOP原始版本的重構過程。通過該重構,力圖將一個雜亂無章的遺留代碼重構為有良好測試的、結構良好、可讀性較強的高質量代碼。

在本次重構中,我不但會對代碼結構進行重構,還會改變部分行為(如將“抽象類要檢查是否實現了接口成員和父類的抽象方法”修改為“抽象類不檢查是否實現了接口成員和父類的抽象方法”;將“抽象類、類只能繼承1個接口”修改為“可以繼承多個接口”等等)。改變行為時,必須先添加或者修改測試,然后才能小步地改變行為。

原始版本

(function () {

    /************************************************** String對象擴展 ***********************************************************
    
    擴展方法:
    contain
    containIgnoreCase
    trim

    */
    if (!String.prototype.contain) {
        String.prototype.contain = function (str) {
            /* 使用RegExp對象來構造動態匹配。
            注意!str是字符串,因此需要轉義!

            由於JavaScript字符串中的“\”是一個轉義字符,因此,使用顯式構造函數創建RegExp實例對象時,應將原始正則表達式中的“\”用“\\”替換。例如,在代碼1.2中的兩條語句是等價的。

            代碼1.2   轉義字符中的“\”:1.2.htm

            <script language="javascript">

            var re1 = new RegExp("\\d{5}");

            var re2 = /\d{5}/;

            alert("re1="+re1+"\nre2="+re2);

            </script>

         

            由於正則表達式模式文本中的轉義字符也是“\”,如果正則表達式中要匹配原義字符“\”,在正則表達式模式文本中要以“\\”來表示,當使用顯式構造函數的方式創建RegExp實例對象的時候,就需要使用“\\\\”來表示原義字符“\”。

            var re = new RegExp(\\\\)。

            */
            var reg = new RegExp(str);
            if (this.match(reg)) {  //用this指針指代本體
                return true;
            }
            else {
                return false;
            }
        }
    }

    /*****************************************************************************************************************************/


    //當前是否處於創建類的階段。
    //放在自執行函數中,initializing就是自執行函數的內部變量,自執行函數的上下文結束后,外部就不能訪問initializing了。
    //不用var的話,就不是當前上下文的一個變量了,而是全局對象的一個屬性。這樣外部就能夠訪問了。
    var initializing = false;
    //    var count = 0;


    //獲得函數的參數數組
    function argumentNames(fn) {
        var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1].replace(/\s+/g, '').split(',');
        return names.length == 1 && !names[0] ? [] : names;
    };

    /* 深拷貝
    */
    function extendDeep(parent, child) {
        var i,
                toStr = Object.prototype.toString,
                sArr = "[object Array]",
                sOb = "[object Object]",
                type = "",
        child = child || {};

        for (i in parent) {
            //if (parent.hasOwnProperty && parent.hasOwnProperty(i)) {

            //                if (typeof parent[i] === 'object') {    //null === 'object'也為true!

            type = toStr.call(parent[i]);
            if (type === sArr || type === sOb) {    //如果為數組或object對象
                child[i] = type === sArr ? [] : {};
                extendDeep(parent[i], child[i]);
            } else {
                child[i] = parent[i];
            }
        }
        //}
        return child;
    };


    //獲得函數名
    function getFunctionName(fn) {
        var name = "";

        if (!fn) {
            return null;
        }

        name = fn.toString().match(/^.*function\s*([^\(]*)/);
        return name === null ? name : name[1];
    };

    //判斷是否為數組
    function isArray(val) {
        return Object.prototype.toString.call(val) === "[object Array]";
    };

    //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
    //不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
    function check(parentClass, interface, children) {
        //        if (!parent || !interface || !children) {
        //            throw new Error("check - arguments error!");
        //        }

        var name = "";

        if (parentClass) {
            //檢查是否實現了抽象方法/屬性
            for (name in parentClass.prototype) {
                if (parentClass.prototype.hasOwnProperty(name)) {
                    //                console.log(name);
                    if (name === "constructor") {
                        continue;
                    }
                    if (name.contain("Abstract_")) {
                        //抽象方法
                        if (typeof parentClass.prototype[name] === "function") {
                            if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                                //                            var t = name.slice(9);
                                throw new Error("Abstract method '" + name + "' must be overwrited!");
                            }
                        }
                            //抽象屬性
                        else {
                            if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                                //                            var t = name.slice(9);
                                //                            var p = children[name.slice(9)];
                                //                            var q = typeof children[name.slice(9)];
                                throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                            }
                        }
                    }
                }
            }
        }

        if (!interface) {
            return;
        }

        //檢查是否實現了接口方法/屬性
        for (name in interface.prototype) {
            //                console.log(name);
            if (name === "constructor") {
                continue;
            }
            //                if (interface.prototype.hasOwnProperty(name)) {
            //接口方法
            if (typeof interface.prototype[name] === "function") {
                //                    var t = name.slice(10);
                //                    var m = children[name.slice(10)];
                //                        console.log("t = " + t);
                //                        console.log("m = " + m);
                if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                    throw new Error("Interface method '" + name + "' must be overwrited!");
                }
            }
                //接口屬性
            else {
                //                    var t = name.slice(10);
                //                    var m = children[name.slice(10)];
                //                        console.log("t = " + t);
                //                        console.log("m = " + m);
                if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                    throw new Error("Interface attribute '" + name + "' must be overwrited!");
                }
            }
            //                }
        }
    };

    //檢查抽象成員
    function addAbstract(abstract, currentClass, temp) {
        var name = "";

        for (name in abstract) {
            if (abstract.hasOwnProperty(name)) {
                //                if (typeof abstract[name] !== "function") {
                //                    throw new Error("Virtual attribute is not allowed!");
                //                }
                //                else {
                //抽象方法前面加"Abstract_"前綴
                currentClass.prototype["Abstract_" + name] = abstract[name];
                //                currentClass.prototype[name] = abstract[name];

                temp[name] = abstract[name];    //加入temp
                //                }
            }
        }
    };

    //檢查虛方法(不能為虛屬性)
    function addVirtual(virtual, currentClass, temp) {
        var name = "";

        for (name in virtual) {
            if (virtual.hasOwnProperty(name)) {
                if (typeof virtual[name] !== "function") {
                    throw new Error("Virtual attribute is not allowed!");
                }
                else {
                    currentClass.prototype[name] = virtual[name];

                    temp[name] = virtual[name];    //加入temp
                }
            }
        }
    };

    //加入密封方法。
    //沒有實現檢查子類是否重寫了父類的密封方法,只是定義了一個規范。
    function addSealed(sealed, currentClass, temp) {
        var name = "";

        for (name in sealed) {
            if (sealed.hasOwnProperty(name)) {
                currentClass.prototype[name] = sealed[name];

                temp[name] = sealed[name];    //加入temp
            }
        }
    };

    //獲得在原型prototype中不存在同名的str。
    //如果有同名,則加上前綴"_"
    function getNoRepeatStrInPrototype(prototype, str) {
        var new_str = "";

        if (!prototype[str]) {
            return str;
        }

        new_str = "_" + str;
        return getNoRepeatStrInPrototype(prototype, new_str);
    }




    //創建接口
    //接口可以繼承接口
    function MyInterface(_parent, _method, _attribute) {
        var i = 0, args = null;

        var parent = null,
            method = null,
            attribute = null;

        if (typeof _parent === "function") {
            if (getFunctionName(_parent) !== "I") {
                throw new Error("Interface must inherit interface!");
            }
            else {
                parent = _parent;

                //形如“MyInterface(Parent, "A", "B", "GetName");”
                if (_method && !isArray(_method)) {
                    method = Array.prototype.slice.call(arguments, 1);
                    attribute = null;
                }
                    //形如“MyInterface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                else {
                    method = _method;
                    attribute = _attribute;
                }
            }
            //            console.log(parent.toString());
        }
        else {
            parent = null;
            //形如“MyInterface("A", "B", "GetName");”
            if (_method && !isArray(_method)) {
                method = arguments
                attribute = null;
            }
                //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
            else {
                method = arguments[0];
                attribute = arguments[1];
            }
        }

        function I() {
        }

        // 如果此接口需要從其它接口擴展
        if (parent) {
            I.prototype = new parent();
            I.prototype.constructor = I;
        }

        //        console.log("method = " + method);
        //        console.log("attribute = " + attribute);


        //        //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
        //        if (isArray(method)) {

        //方法
        for (i = 0; i < method.length; i++) {
            //加上前綴“Interface_”
            I.prototype["Interface_" + method[i]] = function () {
                throw new Error("This method must be overwrited!");
            };
        }
        //屬性
        if (attribute) {
            if (!isArray(attribute)) {
                throw new Error("Attribute must be array!");
            }
            else {
                for (i = 0; i < attribute.length; i++) {
                    //加上前綴“Interface_”
                    I.prototype["Interface_" + attribute[i]] = 0;
                }
            }
        }
        //        }
        //        //形如“MyInterface("A", "B", "GetName");”
        //        else {
        //            args = Array.prototype.slice.call(arguments, 1);
        //            //方法
        //            for (i = 0; i < args.length; i++) {
        //                I.prototype[args[i]] = function () {
        //                    throw new Error("This method must be overwrited!");
        //                };
        //            }
        //        }

        return I;
    };



    //創建抽象類
    //抽象類能夠繼承接口、抽象類以及實體類,但此處約定抽象類只能繼承接口和抽象類,不能繼承實體類!
    //(這樣方便判斷抽象類是否包含全部的父類(接口/抽象類)成員)
    function MyAbstract(_parent, _prop) {
        var Static = null;
        var k = null, name = null, temp = {},
            virtual = {};

        //        if (arguments.length > 1) {
        //            throw new Error("AbstractClass can't inherit other classes!");
        //        }

        var abstractClass = null,
                interface = null,
            prop = null;

        //原型恢復標志,用於防止第一次創建實例時恢復原型
        var mark_resume = false;


        //取出父類、接口
        if (arguments.length === 1) {
            prop = arguments[0];
            //            parent = null;
            abstractClass = null;
            interface = null;
        }
            //_parent為{Class: xx, Interface: xx}
        else if (typeof _parent === "object") {

            if (!_parent.Class && !_parent.Interface) {
                throw new Error("Please add AbstractClass or Interface!");
            }
            if (getFunctionName(_parent.Class) === "F" || getFunctionName(_parent.Interface) === "F") {
                throw new Error("AbstractClass here can't inherit parentClass which is created by MyClass function!");
            }

            abstractClass = _parent.Class;
            interface = _parent.Interface;

            prop = _prop;
        }
            //_parent直接為xx,就表示父類為抽象類
        else if (typeof _parent === "function") {
            if (getFunctionName(_parent) === "F") {
                throw new Error("AbstractClass here can't inherit parentClass which is created by MyClass function!");
            }

            abstractClass = _parent;
            interface = null;

            prop = _prop;
        }
        else {
            throw new Error("arguments is not allowed!");
        }


        Static = prop.Static ? prop.Static : null;


        // 本次調用所創建的類(構造函數)
        function A() {
            //            // 如果抽象父類存在,則實例對象的baseClass指向父類的原型
            //            // 這就提供了在實例對象中調用父類方法的途徑
            //            if (abstractClass) {
            //                this.baseClass = abstractClass.prototype;
            //            }

            ////防止第一次創建實例時恢復原型
            //if (mark_resume) {
            //    //還原原型
            //    extendDeep(A.prototype.backUp_prototype, A.prototype);
            //}
            //else {
            //    mark_resume = true;
            //}

        }

        // 如果此接口需要從其它接口擴展
        if (abstractClass) {
            //            //刪除父類的私有成員,保留本類的私有成員
            //            for (name in abstractClass.prototype) {
            //                if (abstractClass.prototype.hasOwnProperty(name)) {
            //                    //私有成員以“_”開頭,可能有多個“_”(多層繼承)
            //                    if (!name.match(/^_+/)) {
            //                        //                                                delete parentClass.prototype[name];
            //                        A.prototype[name] = abstractClass.prototype[name];
            //                    }
            //                }
            //            }

            //A.prototype = new abstractClass();
            A.prototype = extendDeep(abstractClass.prototype);

            A.prototype.constructor = A;

            // 如果父類存在,則實例對象的baseClass指向父類的原型。
            // 這就提供了在實例對象中調用父類方法的途徑。
            //baseClass的方法是指向abstractClass的,不是指向F(子類)的!

            A.prototype[getNoRepeatStrInPrototype(abstractClass.prototype, "baseClass")] = abstractClass.prototype;
            //A.prototype.baseClass = abstractClass.prototype;
        }

        //加入構造函數
        //抽象類本身因為不能實例化,所以不調用構造函數。
        //抽象類中的構造函數供子類構造函數中調用。
        if (prop.Init) {
            if (abstractClass) {
                A.prototype.Init = function (name) {
                    return function () {
                        //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                        this.base = function () {
                            //這個寫法也可以!為什么不用apply修正this也行??!
                            //parentClass.prototype[name](); 

                            //此處的arguments為base方法傳入的形參
                            //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                            return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
                        };
                        //指向子類,可以用於模版模式
                        this.baseToSubClass = abstractClass.prototype[name];

                        //執行fn並返回執行的結果
                        //此處的arguments為F.prototype[name]方法傳入的形參。
                        return prop[name].apply(this, arguments);
                    };

                }("Init");
            }
            else {
                A.prototype.Init = prop.Init;
            }
        }

        if (prop.Private) {
            //私有屬性/方法直接覆蓋
            for (name in prop.Private) {
                if (prop.Private.hasOwnProperty(name)) {
                    A.prototype[name] = prop.Private[name];
                }
            }
        }

        if (prop.Public) {
            for (name in prop.Public) {
                if (prop.Public.hasOwnProperty(name)) {
                    //檢查抽象成員,抽象成員放到Public或Protected中
                    if (name === "Abstract") {
                        addAbstract(prop["Public"][name], A, temp);
                        continue;
                    }
                    //檢查虛方法,虛方法放到Public或Protected中
                    if (name === "Virtual") {
                        addVirtual(prop["Public"][name], A, temp);
                        continue;
                    }
                    //密封的方法(不允許子類重寫)
                    if (name === "Sealed") {
                        addSealed(prop["Public"][name], A, temp);
                        continue;
                    }

                    if (abstractClass &&
            typeof prop.Public[name] === "function" &&
            typeof A.prototype[name] === "function") {
                        A.prototype[name] = function (name) {
                            return function () {
                                //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                                this.base = function () {
                                    //這個寫法也可以!為什么不用apply修正this也行??!
                                    //parentClass.prototype[name](); 

                                    //此處的arguments為base方法傳入的形參
                                    //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                    return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
                                };
                                //指向子類,可以用於模版模式
                                this.baseToSubClass = abstractClass.prototype[name];

                                //執行fn並返回執行的結果
                                //此處的arguments為F.prototype[name]方法傳入的形參。
                                return prop.Public[name].apply(this, arguments);
                            };

                        }(name);
                    }
                    else {
                        A.prototype[name] = prop.Public[name];
                    }



                    temp[name] = prop.Public[name];    //用於檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
                }
            }
        }
        //保護成員
        if (prop.Protected) {
            for (name in prop.Protected) {
                if (prop.Protected.hasOwnProperty(name)) {
                    //檢查抽象成員,抽象成員放到Public或Protected中
                    if (name === "Abstract") {
                        addAbstract(prop["Protected"][name], A, temp);
                        continue;
                    }
                    //檢查虛方法,虛方法放到Public或Protected中
                    if (name === "Virtual") {
                        addVirtual(prop["Protected"][name], A, temp);
                        continue;
                    }
                    //密封的方法(不允許子類重寫)
                    if (name === "Sealed") {
                        addSealed(prop["Protected"][name], A, temp);
                        continue;
                    }
                    A.prototype[name] = prop.Protected[name];

                }
            }
        }





        //        //虛方法(不能為虛屬性)
        //        if (prop.Virtual) {
        //            for (name in prop.Virtual) {
        //                if (prop.Virtual.hasOwnProperty(name)) {
        //                    if (typeof prop.Virtual[name] !== "function") {
        //                        throw new Error("Virtual attribute is not allowed!");
        //                    }
        //                    else {
        //                        //                        //虛方法前面加"Virtual_"前綴,在子類中要檢查虛方法
        //                        A.prototype[name] = prop.Virtual[name];

        //                        temp[name] = prop.Virtual[name];    //用於檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
        //                    }
        //                }
        //            }
        //        }


        //抽象類可以沒有抽象成員
        //        if (!prop.Abstract) {
        //            throw new Error("AbstractClass must have abstract methods!");
        //        }

        //放到外面的抽象成員,默認為公有抽象成員
        for (name in prop.Abstract) {
            if (prop.Abstract.hasOwnProperty(name)) {
                //                console.log();
                //抽象方法前面加"Abstract_"前綴
                A.prototype["Abstract_" + name] = prop.Abstract[name];

                temp[name] = prop.Abstract[name];   //用於檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
            }
        }

        //        //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性
        //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的接口方法/屬性
        check(null, interface, temp);

        //靜態屬性/方法賦值
        for (k in Static) {
            A[k] = Static[k];
        }

        ////備份原型
        //A.prototype.backUp_prototype = extendDeep(A.prototype);

        return A;
    }



    //    //是否調用父類函數
    //    var base_flag = false;

    //創建普通類
    //父類_parent可以為{Class: xx, Interface: xx},或者直接為xx類
    function MyClass(_parent, _prop) {
        //        console.log("length = " + arguments.length);
        var Static = null;
        //                    Private = null,
        //            Public = null,
        //            Origin = null;

        var k = null, name = null;

        var parentClass = null, interface = null, prop = null, temp = {};
        //        var temp = null;

        //        //原型備份容器,用於創建實例時,恢復最初的原型(每次創建實例時,原型都保持不變)。
        //        var backUp_prototype = {};

        //原型恢復標志,用於防止第一次創建實例時恢復原型
        var mark_resume = false;


        //取出父類、接口
        if (arguments.length === 1) {
            prop = arguments[0];
            parentClass = null;
            interface = null;
        }
            //{Class: xx, Interface: xx}
        else if (typeof _parent === "object") {
            //            if (parent.Class)
            if (!_parent.Class && !_parent.Interface) {
                throw new Error("Please add Class or Interface!");
            }

            parentClass = _parent.Class;
            interface = _parent.Interface;

            prop = _prop;
        }
            //直接為xx類
        else if (typeof _parent === "function") {
            parentClass = _parent;
            interface = null;
            //            parent = _parent;
            //            interface = null;

            prop = _prop;
        }
        else {
            throw new Error("arguments is not allowed!");
        }



        //取出靜態屬性/方法、私有屬性/方法、公有屬性/方法
        //        Private = prop.Private;

        //        Public = prop.Public;

        Static = prop.Static ? prop.Static : null;



        //        //保存原始的私有屬性,用於創建實例時,重置私有屬性
        //        //        var Origin = {};
        //        //        Origin = Private
        //        Origin = operate.extendDeep(Private);
        //        YYC.Tool.extend.extend(Origin, Private);


        //        //訪問公共屬性/方法的入口,
        //        MyClass.Public = Public;


        // 本次調用所創建的類(構造函數)
        function F() {
            //            console.log(mark_resume);



            //防止第一次創建實例時恢復原型
            if (mark_resume) {
                //var t = F.prototype.backUp_prototype;
                //var m = F.prototype;

                //還原原型
                //extendDeep(F.prototype.backUp_prototype, F.prototype);
                extendDeep(F.backUp_prototype, F.prototype);


                //F.prototype.backUp_prototype = extendDeep(F.prototype);
            }
            else {
                mark_resume = true;
            }

            // 如果當前處於實例化類的階段,則調用Init原型函數
            if (!initializing) {
                //                console.log("F");
                //                // 如果父類存在,則實例對象的baseClass指向父類的原型
                //                // 這就提供了在實例對象中調用父類方法的途徑
                //                if (parentClass) {
                //                    this.baseClass = parentClass.prototype;
                //                    //                    console.log(this.baseClass);
                //                }
                this.Init && this.Init.apply(this, arguments);
            }

            //            this.Public = Public;

            //            console.log("F");


            //            if (this.)
            //            console.log(this._m);
            //            delete this._m;

            //            delete F.prototype._m;
            //            delete F.prototype._a;
            //            this._m = null;
            //            this._a = null;
            //            delete F.prototype._a;



            /*不能刪除私有成員和保護成員!否則類的成員就不能調用到私有和保護的成員了(因為已經刪除了)!
            對象的創建算法參考http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html




            //刪除私有成員和保護成員,這樣外界就不能訪問私有和保護成員了!
            for (name in this) {
            if (name.search(/(^_)|(^P_)/) !== -1) {
            delete F.prototype[name];
            //                                                    this[name] = null;
            }
              
            }
            */



            //            console.log(count);
            //            count++;

            //不使用MyClass.self!因為該屬性為靜態屬性,如果創建了該類后,又創建了類A,則MyClass.self會指向類A!

            //            MyClass的靜態屬性self指向創建的類的實例,可以通過self來訪問實例的屬性和方法
            //            MyClass.self = this;





            //            Private.C();

            //            for (name in Private) {
            //                Private[name].call(this);
            //            }




        }




        //        Private.C = Private.C.call(null, Public);

        //        Private.call(F, null);

        //                Private.M = (function (pub) {
        //                    return function () {
        //                        Private.M.call(null, arguments);
        //                    }
        //                }(Public));


        //        for (name in Private) {
        //            Private[name] = function () {
        //                //            console.log("1111111");
        //                return function () {
        //                    //                console.log("222222222");
        //                    return Private[name].call(this, arguments);
        //                }

        //            };
        //        }



        //        Private.C = function () {
        //            return function () {
        //                Private.C.call(F, arguments);
        //            }
        //        };


        // 如果此類需要從其它類擴展
        if (parentClass) {

            initializing = true;
            //F.prototype = new parentClass();
            F.prototype = extendDeep(parentClass.prototype);


            F.prototype.constructor = F;

            //            for (name in parentClass.prototype) {
            //                if (parentClass.prototype.hasOwnProperty(name)) {
            //                    //私有成員不繼承
            //                    if (!name.match(/^_/)) {
            //                        F.prototype[name] = parentClass.prototype[name];
            //                    }
            //                }
            //            }

            //            //刪除父類的私有成員,保留本類的私有成員
            //            for (name in parentClass.prototype) {
            //                if (parentClass.prototype.hasOwnProperty(name)) {
            //                    //私有成員以“_”開頭,可能有多個“_”(多層繼承)
            //                    if (!name.match(/^_+/)) {
            //                        //                                                delete parentClass.prototype[name];
            //                        F.prototype[name] = parentClass.prototype[name];
            //                    }
            //                }
            //            }

            //            console.log(F.prototype.constructor);


            // 如果父類存在,則實例對象的baseClass指向父類的原型。
            // 這就提供了在實例對象中調用父類方法的途徑。
            //baseClass的方法是指向parentClass的,不是指向F(子類)的!
            //F.prototype.baseClass = parentClass.prototype;


            F.prototype[getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;

            initializing = false;
        }

        if (prop.Init) {



            // 如果此類繼承自父類parent並且父類原型中存在同名函數name
            if (parentClass &&
    typeof prop.Init === "function" &&
    typeof F.prototype.Init === "function") {
                F.prototype.Init = function (name) {
                    return function () {
                        this.base = function () {
                            return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                        };
                        //指向子類,可以用於模版模式
                        this.baseToSubClass = parentClass.prototype[name];
                        //執行fn並返回執行的結果
                        //此處的arguments為F.prototype[name]方法傳入的形參。
                        return prop[name].apply(this, arguments);
                    };

                }("Init");
            }
            else {
                F.prototype.Init = prop.Init;
            }
        }


        //        Private.call(this);

        //        if (parentClass && parentClass.prototype["JudgeDoubleHit"]) {
        //            console.log(parentClass.toString());


        if (parentClass) {
            for (name in parentClass.prototype) {
                if (parentClass.prototype.hasOwnProperty(name)) {
                    //如果不是抽象方法/保護方法/私有方法/接口成員,則加入到temp中。
                    //用於添加父類的密封方法(因為子類並沒有加入父類的密封方法)。
                    if (!name.match(/^Abstract_/) || !name.match(/^P_/) || !name.match(/^_/) || !name.match(/^Interface_/)) {
                        temp[name] = parentClass.prototype[name];
                    }
                }
            }
        }





        //        }

        //        if (this.baseClass.Protected) {
        //            if (this.baseClass.Protected.Sealed) {

        //                for (k in this.baseClass.Protected.Sealed) {
        //                    temp[k] = this.baseClass.Protected.Sealed[k];
        //                }
        //            }
        //        }


        if (prop.Private) {
            //私有屬性/方法直接覆蓋
            for (name in prop.Private) {
                if (prop.Private.hasOwnProperty(name)) {
                    F.prototype[name] = prop.Private[name];
                }
            }
        }

        //        if (!prop.Public) {
        //            throw new Error("Class must have public methods!");
        //        }
        //        else {

        //        }


        //保護成員
        if (prop.Protected) {
            for (name in prop.Protected) {
                if (prop.Protected.hasOwnProperty(name)) {
                    //檢查虛方法,虛方法放到Public或Protected中
                    if (name === "Virtual") {
                        addVirtual(prop["Protected"][name], F, temp);
                        continue;
                    }
                    //密封的方法(不允許子類重寫)
                    if (name === "Sealed") {
                        addSealed(prop["Protected"][name], F, temp);
                        continue;
                    }

                    F.prototype[name] = prop.Protected[name];

                    //如果父類有保護抽象成員,此處檢查子類的保護成員是否實現了父類的保護抽象成員
                    temp[name] = prop.Protected[name];
                }
            }
        }

        //        //虛方法(不能為虛屬性)
        //        if (prop.Virtual) {
        //            for (name in prop.Virtual) {
        //                if (prop.Virtual.hasOwnProperty(name)) {
        //                    if (typeof prop.Virtual[name] !== "function") {
        //                        throw new Error("Virtual attribute is not allowed!");
        //                    }
        //                    else {
        //                        F.prototype[name] = prop.Virtual[name];

        //                        temp[name] = prop.Virtual[name];    //加入temp
        //                    }
        //                }
        //            }
        //        }

        if (prop.Abstract) {
            throw new Error("Only abstractClass can have abstract methods!");
        }



        if (prop.Public) {
            // 覆蓋父類的同名公有方法
            for (name in prop.Public) {
                //            console.log("for in name = " + name);
                //            //私有屬性/方法不加入到原型中
                //            if (name === "Private") {
                ////                console.log("continue");
                //                continue;
                //            }

                if (prop.Public.hasOwnProperty(name)) {
                    //檢查虛方法,虛方法放到Public或Protected中
                    if (name === "Virtual") {
                        addVirtual(prop["Public"][name], F, temp);
                        continue;
                    }
                    //密封的方法(不允許子類重寫)
                    if (name === "Sealed") {
                        addSealed(prop["Public"][name], F, temp);
                        continue;
                    }
                    //                    console.log("Public");
                    //                    console.log("name = " + name);
                    //                    console.log("prop.Public[name] = " + prop.Public[name]);
                    temp[name] = prop.Public[name];     //加入temp

                    // 如果此類繼承自父類parent並且父類原型中存在同名函數name
                    if (parentClass &&
            typeof prop.Public[name] === "function" &&
            typeof F.prototype[name] === "function") {
                        //                        console.log("parent!");




                        F.prototype[name] = function (name) {
                            return function () {
                                /*此處如果寫成“this.base = parentClass.prototype[name];”,則在使用this.base()調用父類同名方法時,
                                父類同名方法的this指針是指向F的!(即指向子類,而不是指向父類!)   為什么????
                                如:
                                var Person = MyAbstract({
                                Init: function (name) {
                                this.name = name;
                                },
                                Public: {
                                m: 1,
                                getEmployeeID: function () {
                                console.log(this.m);
                                }
                                }
                                }
                                });


                                var Employee = MyClass({
                                Init: function (name) {
                                this.name = name;
                                },
                                Public: {
                                m: 100,
                                getEmployeeID: function () {
                                this.baseClass.getEmployeeID();
                                this.base();
                                }
                                }
                                });

                                var m = new Employee();
                                m.getEmployeeID();    //輸出:1  100

                                分析:
                            
                                this.baseClass.getEmployeeID()的this指向Person,而this.base()的this指向Employee!

                                解決方案:

                                用apply修正this.base()中的this,使其指向父類。
                                */


                                //                                if (!this.base) {
                                //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                                this.base = function () {
                                    //這個寫法也可以!為什么不用apply修正this也行??!
                                    //parentClass.prototype[name](); 

                                    //此處的arguments為base方法傳入的形參
                                    //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                    return parentClass.prototype[name].apply(parentClass.prototype, arguments);

                                    //                                    this.baseClass.
                                };
                                //                                }
                                //                                if (!this.baseToSubClass) {
                                //指向子類,可以用於模版模式
                                this.baseToSubClass = parentClass.prototype[name];
                                //                                }

                                //                                this.base = function () {
                                //                                    //                                    console.log(base_flag);

                                //                                    Private = {
                                //                                    };
                                ////                                    base_flag = true;
                                //                                    return parent.prototype[name];
                                //                                };
                                //                            console.log("arg = " + arg);

                                //執行fn並返回執行的結果
                                //此處的arguments為F.prototype[name]方法傳入的形參。
                                return prop.Public[name].apply(this, arguments);
                            };

                        }(name);

                    }
                    else {
                        //                    console.log();
                        //公有屬性
                        if (typeof (prop.Public[name]) !== "function") {
                            F.prototype[name] = prop.Public[name];
                        }
                            //公有方法
                        else {
                            /* 如果不傳入Public[name],而直接在自執行函數中調用Public[name],如
                            F.prototype[name] = function () {
                            return function () {
                            prop.Public[name].apply(this, arguments);
                            };
                            } ();

                            或者寫成:
                            F.prototype[name] = function () {
                            prop.Public[name].call(this, arguments);
                            };
                        
                        
                            這樣的話,在創建實例時調用方法時,都會執行MyClass中的最后一個函數!見下例
                        
                            var Person = MyClass({
                            Init: function (name) {
                            this.name = name;
                            },
                            getName: function () {
                            console.log("getName");
                            },
                            getEmployeeID: function ($private) {
                            console.log("Person getEmployeeID");
                            }
                            });
                            var m = new Person("name");     
                            m.getName();    //第一種和第二種寫法此處會輸出:"Person getEmployeeID"
                

                            這樣執行的原因是:

                            (引用自“深入理解JavaScript系列(16):閉包(Closures)”)
                            同一個父上下文中創建的閉包是共用一個[[Scope]]屬性的。也就是說,
                            某個閉包對其中[[Scope]]的變量做修改會影響到其他閉包對其變量的讀取。
                            這就是說:所有的內部函數都共享同一個父作用域。

                            也就是說,function里面的name都是共用父作用域中的name!所以此處F.prototype[name]被激活的時候,
                            name都為最后一個值即"getEmployeeID"。
                            所以F原型上的方法都指向"getEmployeeID"

                            解決方案:

                            創建一個閉包來保存name的值。
                            */
                            F.prototype[name] = function (name) {
                                return function () {
                                    return prop.Public[name].apply(this, arguments);     //執行fn並返回執行的結果
                                };
                            }(name);

                        }
                    }
                }
            }
        }




        //檢查公有成員和虛函數是否實現了抽象方法/屬性 或 接口方法/屬性
        check(parentClass, interface, temp);


        //靜態屬性/方法賦值
        for (k in Static) {
            F[k] = Static[k];
        }



        //備份原型
        //F.prototype.backUp_prototype = extendDeep(F.prototype);
        F.backUp_prototype = extendDeep(F.prototype);


        return F;
    };

    YYC.Pattern.namespace("Frame").MyInterface = MyInterface;

    YYC.Pattern.namespace("Frame").MyAbstract = MyAbstract;

    YYC.Pattern.namespace("Frame").MyClass = MyClass;
}());
View Code

代碼分析

我並不打算對代碼詳細說明,因為該文的重點在於展示重構的過程。因此我介紹下原始版本實現OOP的核心內容,具體請參考代碼。

MyInterface為接口,MyAbstract為抽象類,MyClass為類。

創建一個接口,可以這樣寫:

var A = YYC.Frame.MyInterface("method1", "method2");

調用“YYC.Frame.MyInterface”時,會調用MyInterface函數,該函數會把參數解析,把方法和屬性加上前綴“Interface_”,加入到內部函數I.prototype中,然后返回內部函數I。

因此,A就具有了接口方法和接口屬性,但是我們不會直接使用接口(如創建A的實例,訪問接口方法),因為接口的方法和屬性(統稱為成員)並沒有實現,需要在繼承接口的類中實現。

然后創建一個抽象類:

var B = YYC.Frame.MyAbstract({
    Protected: {    //保護成員
        Abstract: { //保護抽象成員
        },
        Virtual: {  //保護虛方法
        },
        P_proA: true,   //保護屬性
        P_proM: function () { }    //保護方法
    },
    Public: {   //公有成員
        Abstract: { //公有抽象成員
        },
        Virtual: {  //公有虛方法
        },
        pubM: function () { },  //公有方法
        pubA: 0    //公有屬性
    },
    Private: {  //私有成員
        _priA: "",   //私有屬性
        _priM: function () { } //私有方法
    },
    Abstract: { //公有抽象成員
    },
    Virtual: {  //公有虛方法
    }
});
View Code

調用“YYC.Frame.MyAbstract”時,會調用MyAbstract函數,該函數會把參數解析,將公有成員、私有成員、保護成員都加入到內部函數A.prototype中(約定私有成員、保護成員的命名規則,約定使用框架者遵守訪問權限)。

抽象成員(Abstract:{}中的成員)先加上前綴“Abstract_”,然后加入到A.prototype中(子類根據前綴來區分判斷是否實現了父類的抽象成員)。

然后創建一個類,繼承接口A和抽象類B:

var C = YYC.Frame.MyClass({Interface: A, Class: B},{
    Init: function () { //構造函數
    },
    Protected: {    //保護成員
    },
    Public: {   
        Virtual: { 
        },
        method1: function () { }, 
        method2: function () { }
    },
    Private: {  //私有成員
        _priA: "",   //私有屬性
        _priM: function () { } //私有方法
    }
});
View Code

調用“YYC.Frame.MyClass”時,會調用MyClass函數,該函數會把參數解析,將公有成員、私有成員、保護成員都加入到內部函數F.prototype中。

構造函數Init在F的構造函數function F(){}中調用,從而在創建C的實例時,會調用構造函數Init。

此處繼承了接口A和抽象類B,因此會先用深拷貝的方法來將A、B的成員加入到F.prototype中,然后判斷是否實現A的接口成員(根據“Interface_”前綴來判斷)、是否實現B的抽象成員(根據“Abstract_”前綴來判斷),如果沒有實現會拋出異常。

為什么要用深拷貝來實現繼承

//F.prototype = new parentClass();
F.prototype = extendDeep(parentClass.prototype);

此處繼承使用深拷貝來實現,原因是為了解決下面的問題:

  • 若父類Parent的屬性為引用類型(數組或對象)a,有兩個子類Sub1、Sub2。如果子類Sub1的實例s1對a進行修改或者sub調用修改a的方法,則子類Sub2的實例的a為修改過后的a!

問題描述

var Parent = YYC.Frame.MyClass({
    Private:{
        _a: []
    },
    Public: {
        add: function () {
            this._a.push("a");
        }
    }
});
var Sub1 = YYC.Frame.MyClass(Parent, {});
var Sub2 = YYC.Frame.MyClass(Parent, {});

var t = new Sub1();
t.add();
console.log(t.a);        //["a"]
var k = new Sub2();
console.log(k.a);    //照理說應該為[],但實際上卻是["a"]!

原因分析

上例中的“t.add();”修改的是實例t的_a屬性,實例t的_a屬性與Parent.prototype._a指向同一個數組。因此修改實例t的_a就相當於修改了Parent.prototype._a。

解決方案

修改類繼承方式,改為通過深拷貝的方式拷貝父類原型的成員來實現繼承:

F.prototype = extendDeep(parentClass.prototype);

這樣實例t的_a屬性和Parent.protype._a就指向不同的數組了。

為什么要重構

原始版本對其它的庫有依賴(如依賴於namespace.js),有太多沒用或錯誤的注釋,混在一起的職責,過於龐大的函數,函數名、屬性名不能很好地體現職責,多層嵌套的條件式等等。另外,最大的問題是沒有對應的測試套件。

開始重構

編寫測試

回到本次重構中來,要進行重構,首先需要堅固的測試作保證。我使用Jasmine作為Javascript的測試工具。建議大家先可以看下javascript單元測試,里面介紹了單元測試的工具,包括Jasmine。

先編寫幾個主要的測試,測試是否解決了我之前發現的幾個問題。

describe("oopFrame", function () {
    describe("測試Class", function () {
        describe("獲得公有成員", function () {
            it("如果父類不存在,能夠正確獲得公有方法", function () {
                var Class = YYC.Frame.MyClass({
                    Public: {
                        a: function () {
                            this.b = 1;
                            return 0;
                        }
                    }
                });

                var cla = new Class();
                var result = cla.a();

                expect(result).toEqual(0);
                expect(cla.b).toEqual(1);
            });
        });
    });

    describe("集成測試", function () {
        it("測試解決“若父類的屬性為引用類型(數組或對象)a,則如果子類的實例s1對a進行修改或者sub調用修改a的方法,則第二次創建實例s2的a為修改過后的a!”的問題", function () {
            var Parent = YYC.Frame.MyAbstract({
                Init: function () {
                    console.log("Parent Init!");
                },
                Public: {
                    a: [],
                }
            });
            var Sub = YYC.Frame.MyClass(Parent, {
                Init: function () {
                },
                Public: {
                }
            });

            var t = new Sub();
            t.a.push("a");
            var m = new Sub();

            expect(m.a).toEqual([]);
        });
        it("測試解決“若父類Parent的屬性為引用類型(數組或對象)a,有兩個子類Sub1、Sub2。如果子類Sub1的實例s1對a進行修改或者sub調用修改a的方法,則子類Sub2的實例的a為修改過后的a!”的問題", function () {
            var Parent = YYC.Frame.MyAbstract({
                Init: function () {
                    console.log("Parent Init!");
                },
                Public: {
                    a: [],
                    add: function () {
                        this.a.push("a");
                    }
                }
            });
            var Sub1 = YYC.Frame.MyClass(Parent, {
                Init: function () {
                },
                Public: {
                }
            });
            var Sub2 = YYC.Frame.MyClass(Parent, {
                Init: function () {
                }
            });

            var t = new Sub1();
            t.a.push("a");
            var k = new Sub2();

            expect(k.a).toEqual([]);

        });
        it("測試解決“若A1為抽象類,A2(抽象類)繼承於A1,B(類)繼承於A2,A1、A2、B都有同名方法a,A2和B在a方法中都通過this.baseClass調用父類同名方法。則如果B的實例b調用a方法,則A2、B的a方法中的this.baseClass均指向A2(照理說A2的this.baseClass應該指向A1)!”的問題", function () {
            var A1 = YYC.Frame.MyAbstract({
                Public: {
                    arr: [],
                    a: function () {
                        this.arr.push(1);
                    }
                }
            });
            var A2 = YYC.Frame.MyAbstract(A1, {
                Public: {
                    a: function () {
                        this.arr.push(2);
                        this.baseClass.a.call(this, null);
                    }
                }
            });
            var B = YYC.Frame.MyClass(A2, {
                Public: {
                    a: function () {
                        this.arr.push(3);
                        this._baseClass.a.call(this, null);

                        return this.arr;
                    }
                }
            });
            var b = new B();

            expect(b.a()).toEqual([3, 2, 1]);
        });
    });
});
View Code

現在測試的覆蓋面還不全,有些代碼沒有測試到。不過我們已經構建了主要的測試,剩下的測試可以在后續的重構中逐漸加入。

測試頁面

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE HTML>
<html>
<head id="Head1" runat="server">
   <title>Jasmine Spec Runner</title>
  <link rel="stylesheet" type="text/css" href="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine.css") %>" />
        <script src="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine.js") %>"></script>
    <script src="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine-html.js") %>"></script>
  <!-- include source files here... -->
    <script src="<%=Url.Content("~/Scripts/jquery-1.7.js")%>"></script>
    <script src="../../Scripts/myTool/pattern/createObject/namespace.js"></script>
    <script src="<%=Url.Content("~/Scripts/myTool/frame/YOOP.js")%>"></script>
  <!-- include spec files here... -->
    <script src="<%=Url.Content("~/Scripts/jasmine/spec/helper/specHelper.js")%>"></script>
    <script src="../../Scripts/jasmine/spec/frameSpec/YOOPSpec.js"></script>
</head>
<body>


  <script type="text/javascript">
      (function () {
              var jasmineEnv = jasmine.getEnv();
              jasmineEnv.updateInterval = 1000;

              var htmlReporter = new jasmine.HtmlReporter();

              jasmineEnv.addReporter(htmlReporter);

              jasmineEnv.specFilter = function (spec) {
                  return htmlReporter.specFilter(spec);
              };
              function execJasmine() {
                  jasmineEnv.execute();
              }


              var currentWindowOnload = window.onload;



              if (currentWindowOnload) {
                  currentWindowOnload();
              }
              execJasmine();
      })();
</script>

</body>
</html>
View Code

在測試頁面中運行測試,通過全部測試。

解除對其它庫的依賴

現在該框架通過了測試,能夠正常工作。但是因為它采用命名空間模式,需要依賴於namespace.js庫。

我想解除這個依賴,因此直接在框架中定義YYC命名空間,並且考慮到該框架的通用性較高,因此將其命名空間YYC.Frame更改為YYC。

修改框架為:

window.YYC = window.YYC || {};
...
YYC.MyInterface = MyInterface;
YYC.MyAbstract = MyAbstract;
YYC.MyClass = MyClass;

測試頁面中去掉對namespace.js的引用。

修改類名 

類名MyInterface、MyAbstract、MyClass太長了,而且個人氣息太濃,因此將類名改為Interface、AClass、Class。

重構this.base,this.baseToSubClass

原始版本:

A.prototype[name] = function (name) {
    return function () {
        //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
        this.base = function () {
            //這個寫法也可以!為什么不用apply修正this也行??!
            //parentClass.prototype[name](); 

            //此處的arguments為base方法傳入的形參
            //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
            return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
        };
        //指向子類,可以用於模版模式
        this.baseToSubClass = abstractClass.prototype[name];

        //執行fn並返回執行的結果
        //此處的arguments為F.prototype[name]方法傳入的形參。
        return prop.Public[name].apply(this, arguments);
    };

}(name);

原版中,子類使用this.base調用父類同名函數(函數中this指向父類同名函數),子類使用this.baseToSubClass調用父類同名函數(函數中this指向子類同名函數)。

考慮到一般都是使用this.baseToSubClass,因此將this.base改名為this.baseToParent,this.baseToSubClass改名為this.base,並不再使用this.baseToParent。

重構版本:

return function () {
    /*
    //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
    this.baseToParrent = function () {
        //這個寫法也可以!為什么不用apply修正this也行??!
        //parentClass.prototype[name](); 

        //此處的arguments為baseToParrent方法傳入的形參
        //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
        return parentClass.prototype[name].apply(parentClass.prototype, arguments);
    };
    */
    //指向子類,可以用於模版模式
    this.base = parentClass.prototype[name];

    //執行fn並返回執行的結果
    //此處的arguments為F.prototype[name]方法傳入的形參。
    return prop[name].apply(this, arguments);
};

重構結構

分析代碼結構,發現AClass與Class聯系的比較緊密,而Interface則可以單獨為一塊,因此對代碼進行分塊:

(function(){    //A結構
    (function(){    //A1結構
        function Interface(){
        };

        YYC.Interface = Interface;
    }());

    (function(){    //A2結構
        function AClass(){
        };

        function Class(){
        };

        YYC.AClass = AClass;
        YYC.Class = Class;
    }());
}());

提取工具函數

在工具函數的名字中加入前綴“_”,表示為私有函數。

將Interface、AClass、Class共用的工具函數提出來,放到A中。然后將AClass、Class共用的工具函數提出來放到A2中:

(function(){    //A結構
    window.YYC = window.YYC || {};

    /************************************************** String對象擴展 ***********************************************************
    
    擴展方法:
    contain
    containIgnoreCase
    trim

    */
    if (!String.prototype.contain) {
        String.prototype.contain = function (str) {
            var reg = new RegExp(str);
            if (this.match(reg)) {  //用this指針指代本體
                return true;
            }
            else {
                return false;
            }
        }
    }

    /*****************************************************************************************************************************/


    ////獲得函數的參數數組
    //function argumentNames(fn) {
    //    var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1].replace(/\s+/g, '').split(',');
    //    return names.length == 1 && !names[0] ? [] : names;
    //};


    //獲得函數名
    function _getFunctionName(fn) {
        var name = "";

        if (!fn) {
            return null;
        }

        name = fn.toString().match(/^.*function\s*([^\(]*)/);
        return name === null ? name : name[1];
    };

    //判斷是否為數組
    function _isArray(val) {
        return Object.prototype.toString.call(val) === "[object Array]";
    };

    (function(){    //A1結構
        function Interface(){
        };
    }());

    (function(){    //A2結構
        /* 深拷貝
*/
        function _extendDeep(parent, child) {
            var i = null,
            len = 0,
                  toStr = Object.prototype.toString,
                  sArr = "[object Array]",
                  sOb = "[object Object]",
                  type = "",
           _child = null;

            //數組的話,不獲得Array原型上的成員。
            if (toStr.call(parent) === sArr) {
                _child = child || [];

                for (i = 0, len = parent.length; i < len; i++) {
                    type = toStr.call(parent[i]);
                    if (type === sArr || type === sOb) {    //如果為數組或object對象
                        _child[i] = type === sArr ? [] : {};
                        _extendDeep(parent[i], _child[i]);
                    } else {
                        _child[i] = parent[i];
                    }
                }
            }
                //對象的話,要獲得原型鏈上的成員。因為考慮以下情景:
                //類A繼承於類B,現在想要拷貝類A的實例a的成員(包括從類B繼承來的成員),那么就需要獲得原型鏈上的成員。
            else if (toStr.call(parent) === sOb) {
                _child = child || {};

                for (i in parent) {
                    //if (parent.hasOwnProperty && parent.hasOwnProperty(i)) {

                    //                if (typeof parent[i] === 'object') {    //null === 'object'也為true!

                    type = toStr.call(parent[i]);
                    if (type === sArr || type === sOb) {    //如果為數組或object對象
                        _child[i] = type === sArr ? [] : {};
                        _extendDeep(parent[i], _child[i]);
                    } else {
                        _child[i] = parent[i];
                    }
                }
                //}
            }
            else {
                _child = parent;
            }


            return _child;
        };
        //獲得在原型prototype中不存在同名的str。
        //如果有同名,則加上前綴"_"
        function _getNoRepeatStrInPrototype(prototype, str) {
            var new_str = "";

            if (!prototype[str]) {
                return str;
            }
            new_str = "_" + str;

            return _getNoRepeatStrInPrototype(prototype, new_str);
        }

        function AClass(){
        };

        function Class(){
        };

        YYC.AClass = AClass;
        YYC.Class = Class;
    }());
}());
View Code

重構_check函數

注意到_check函數太大,因此需要根據職責來提取出小函數。

_check有兩個職責:

  1. 檢查是否實現了父類的抽象方法/屬性。
  2. 檢查是否實現了接口方法/屬性。

重構前:

function _check(parentClass, interface, children) {
    var name = "";

    if (parentClass) {
        //檢查是否實現了抽象方法/屬性
        for (name in parentClass.prototype) {
            if (parentClass.prototype.hasOwnProperty(name)) {
                if (name === "constructor") {
                    continue;
                }
                if (name.contain("Abstract_")) {
                    //抽象方法
                    if (typeof parentClass.prototype[name] === "function") {
                        if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                            throw new Error("Abstract method '" + name + "' must be overwrited!");
                        }
                    }
                        //抽象屬性
                    else {
                        if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                            throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                        }
                    }
                }
            }
        }
    }
    if (!interface) {
        return;
    }
    //檢查是否實現了接口方法/屬性
    for (name in interface.prototype) {
        if (name === "constructor") {
            continue;
        }
        //接口方法
        if (typeof interface.prototype[name] === "function") {
            if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                throw new Error("Interface method '" + name + "' must be overwrited!");
            }
        }
            //接口屬性
        else {
            if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                throw new Error("Interface attribute '" + name + "' must be overwrited!");
            }
        }
    }
};
View Code

重構后:

//檢查子類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
//不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
function _check(parentClass, interface, children) {
    if (parentClass) {
        _checkAbstract(parentClass, children);
    }
    else if (interface) {
        _checkInterface(interface, children);
    }
};
function _checkAbstract(parentClass, children) {
    var name = "";

    for (name in parentClass.prototype) {
        if (parentClass.prototype.hasOwnProperty(name)) {
            if (name === "constructor") {
                continue;
            }
            if (name.contain("Abstract_")) {
                //抽象方法
                if (typeof parentClass.prototype[name] === "function") {
                    if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                        throw new Error("Abstract method '" + name + "' must be overwrited!");
                    }
                }
                    //抽象屬性
                else {
                    if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                        throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                    }
                }
            }
        }
    }
};
function _checkInterface(interface, children) {
    var name = "";

    for (name in interface.prototype) {
        if (name === "constructor") {
            continue;
        }
        //接口方法
        if (typeof interface.prototype[name] === "function") {
            if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                throw new Error("Interface method '" + name + "' must be overwrited!");
            }
        }
            //接口屬性
        else {
            if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                throw new Error("Interface attribute '" + name + "' must be overwrited!");
            }
        }

    }
};
View Code

_checkAbstract、_checkInterface中的“if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {”等條件語句很難理解,因此將其封裝成函數:

function _checkAbstract(parentClass, children) {
    var name = "";

    for (name in parentClass.prototype) {
        if (parentClass.prototype.hasOwnProperty(name)) {
            if (name === "constructor") {
                continue;
            }
            if (name.contain("Abstract_")) {
                //抽象方法
                if (typeof parentClass.prototype[name] === "function") {
                    if (_noMethodForAbstract(children, name) && _noMethodForAbstract(parentClass.prototype, name)) {
                        throw new Error("Abstract method '" + name + "' must be overwrited!");
                    }
                }
                    //抽象屬性
                else {
                    if (_noAttritubeForAbstract(children, name) && _noAttritubeForAbstract(parentClass.prototype, name)) {
                        throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                    }
                }
            }
        }
    }
};
function _checkInterface(interface, children) {
    var name = "";

    for (name in interface.prototype) {
        if (name === "constructor") {
            continue;
        }
        //接口方法
        if (typeof interface.prototype[name] === "function") {
            if (_noMethodForInterface(children, name) && _noMethodForInterface(parentClass.prototype, name)) {
                throw new Error("Interface method '" + name + "' must be overwrited!");
            }
        }
            //接口屬性
        else {
            if (_noAttritubeForInterface(children, name) && _noAttritubeForInterface(parentClass.prototype, name)) {
                throw new Error("Interface attribute '" + name + "' must be overwrited!");
            }
        }
    }
};
function _noMethodForAbstract(_class, name) {
    return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
};
function _noAttritubeForAbstract(_class, name) {
    return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
};
function _noMethodForInterface(_class, name) {
    return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
};
function _noAttritubeForInterface(_class, name) {
    return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
};
View Code

重構Interface

現在讓我們看下function Interface(){}中的代碼:

//創建接口
//接口可以繼承接口
function Interface(_parent, _method, _attribute) {
    var i = 0, args = null;

    var parent = null,
        method = null,
        attribute = null;

    if (typeof _parent === "function") {
        if (_getFunctionName(_parent) !== "I") {
            throw new Error("Interface must inherit interface!");
        }
        else {
            parent = _parent;

            //形如“MyInterface(Parent, "A", "B", "GetName");”
            if (_method && !_isArray(_method)) {
                method = Array.prototype.slice.call(arguments, 1);
                attribute = null;
            }
                //形如“MyInterface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
            else {
                method = _method;
                attribute = _attribute;
            }
        }
        //            console.log(parent.toString());
    }
    else {
        parent = null;
        //形如“MyInterface("A", "B", "GetName");”
        if (_method && !_isArray(_method)) {
            method = arguments
            attribute = null;
        }
            //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
        else {
            method = arguments[0];
            attribute = arguments[1];
        }
    }

    function I() {
    }

    // 如果此接口需要從其它接口擴展
    if (parent) {
        I.prototype = new parent();
        I.prototype.constructor = I;
    }

    //        console.log("method = " + method);
    //        console.log("attribute = " + attribute);


    //        //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
    //        if (isArray(method)) {

    //方法
    for (i = 0; i < method.length; i++) {
        //加上前綴“Interface_”
        I.prototype["Interface_" + method[i]] = function () {
            throw new Error("This method must be overwrited!");
        };
    }
    //屬性
    if (attribute) {
        if (!isArray(attribute)) {
            throw new Error("Attribute must be array!");
        }
        else {
            for (i = 0; i < attribute.length; i++) {
                //加上前綴“Interface_”
                I.prototype["Interface_" + attribute[i]] = 0;
            }
        }
    }
    //        }
    //        //形如“MyInterface("A", "B", "GetName");”
    //        else {
    //            args = Array.prototype.slice.call(arguments, 1);
    //            //方法
    //            for (i = 0; i < args.length; i++) {
    //                I.prototype[args[i]] = function () {
    //                    throw new Error("This method must be overwrited!");
    //                };
    //            }
    //        }

    return I;
};
View Code

該函數包含了太多的職責,應該把每一個職責提取為一個內部函數,然后再在Interface中調用這些內部函數:

//創建接口
//接口可以繼承接口
function Interface(_parent, _method, _attribute) {
    var i = 0, args = null;
    var parent = null,
        method = null,
        attribute = null;

    function _getByParent() {
        if (typeof _parent === "function") {
            if (_getFunctionName(_parent) !== "I") {
                throw new Error("Interface must inherit interface!");
            }
            else {
                parent = _parent;
                //形如“Interface(Parent, "A", "B", "GetName");”
                if (_method && !_isArray(_method)) {
                    method = Array.prototype.slice.call(arguments, 1);
                    attribute = null;
                }
                    //形如“Interface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                else {
                    method = _method;
                    attribute = _attribute;
                }
            }
        }
        else {
            parent = null;
            //形如“Interface("A", "B", "GetName");”
            if (_method && !_isArray(_method)) {
                method = arguments
                attribute = null;
            }
                //形如“Interface(["A", "B", "GetName"], ["a", "c"]);”
            else {
                method = arguments[0];
                attribute = arguments[1];
            }
        }
    };
    function _inherit() {
        I.prototype = new parent();
        I.prototype.constructor = I;
    };
    function _addMethod() {
        for (i = 0; i < method.length; i++) {
            //加上前綴“Interface_”
            I.prototype["Interface_" + method[i]] = function () {
                throw new Error("This method must be overwrited!");
            };
        }
    };
    function _addAttribute() {
        if (attribute) {
            if (!_isArray(attribute)) {
                throw new Error("Attribute must be array!");
            }
            else {
                for (i = 0; i < attribute.length; i++) {
                    //加上前綴“Interface_”
                    I.prototype["Interface_" + attribute[i]] = 0;
                }
            }
        }
    };

    function I() {
    }

    _getByParent();
    // 如果此接口需要從其它接口擴展
    if (parent) {
        _inherit();
    }
    //方法
    _addMethod();
    //屬性
    _addAttribute();

    return I;
};
View Code

重構AClass、Class

AClass、Class中有一些重復的代碼,將這些重復的代碼提取為函數,放到結構A2中,供AClass、Class調用:

(function(){    //A2結構
    //檢查抽象成員
    function _addAbstract(abstract, currentClass, temp) {
        var name = "";

        for (name in abstract) {
            if (abstract.hasOwnProperty(name)) {
                //抽象方法前面加"Abstract_"前綴
                currentClass.prototype["Abstract_" + name] = abstract[name];
                temp[name] = abstract[name];    //加入temp
            }
        }
    };
    //檢查虛方法(不能為虛屬性)
    function _addVirtual(virtual, currentClass, temp) {
        var name = "";

        for (name in virtual) {
            if (virtual.hasOwnProperty(name)) {
                if (typeof virtual[name] !== "function") {
                    throw new Error("Virtual attribute is not allowed!");
                }
                else {
                    currentClass.prototype[name] = virtual[name];
                    temp[name] = virtual[name];    //加入temp
                }
            }
        }
    };
    //加入密封方法。
    //沒有實現檢查子類是否重寫了父類的密封方法,只是定義了一個規范。
    function _addSealed(sealed, currentClass, temp) {
        var name = "";

        for (name in sealed) {
            if (sealed.hasOwnProperty(name)) {
                currentClass.prototype[name] = sealed[name];
                temp[name] = sealed[name];    //加入temp
            }
        }
    };
    function _addStatic(_class, prop) {
        var Static = null;
        var k = null;

        Static = prop.Static ? prop.Static : null;
        //靜態屬性/方法賦值
        for (k in Static) {
            _class[k] = Static[k];
        }
    };
    function _inherit(_class, parentClass) {
        _class.prototype = _extendDeep(parentClass.prototype);
        _class.prototype.constructor = _class;

        // 如果父類存在,則實例對象的baseClass指向父類的原型。
        // 這就提供了在實例對象中調用父類方法的途徑。
        //baseClass的方法是指向parentClass的,不是指向F(子類)的!
        _class.prototype[_getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
    };
    function _addInit(_class, parentClass, prop) {
        if (prop.Init) {
            // 如果此類繼承自父類parent並且父類原型中存在同名函數name
            if (parentClass &&
    typeof prop.Init === "function" &&
    typeof _class.prototype.Init === "function") {
                //if (parentClass) {
                _class.prototype.Init = function (name) {
                    return function () {
                        /*
                        //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                        this.baseToParrent = function () {
                            //這個寫法也可以!為什么不用apply修正this也行??!
                            //parentClass.prototype[name](); 
    
                            //此處的arguments為baseToParrent方法傳入的形參
                            //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                            return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                        };
                        */
                        //指向子類,可以用於模版模式
                        this.base = parentClass.prototype[name];

                        //執行fn並返回執行的結果
                        //此處的arguments為F.prototype[name]方法傳入的形參。
                        return prop[name].apply(this, arguments);
                    };

                }("Init");
            }
            else {
                _class.prototype.Init = prop.Init;
            }
        }
    };
    function _addPrivate(_class, private) {
        if (private) {
            //私有屬性/方法直接覆蓋
            for (name in private) {
                if (private.hasOwnProperty(name)) {
                    _class.prototype[name] = private[name];
                }
            }
        }
    };
    //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
    //不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
    function _check(parentClass, interface, children) {
        if (parentClass) {
            _checkAbstract(parentClass, children);
        }
        else if (interface) {
            _checkInterface(interface, children);
        }
    };
    function _checkAbstract(parentClass, children) {
        var name = "";

        for (name in parentClass.prototype) {
            if (parentClass.prototype.hasOwnProperty(name)) {
                if (name === "constructor") {
                    continue;
                }
                if (name.contain("Abstract_")) {
                    //抽象方法
                    if (typeof parentClass.prototype[name] === "function") {
                        if (_noMethodForAbstract(children, name) && _noMethodForAbstract(parentClass.prototype, name)) {
                            throw new Error("Abstract method '" + name + "' must be overwrited!");
                        }
                    }
                        //抽象屬性
                    else {
                        if (_noAttritubeForAbstract(children, name) && _noAttritubeForAbstract(parentClass.prototype, name)) {
                            throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                        }
                    }
                }
            }
        }
    };
    function _checkInterface(interface, children) {
        var name = "";

        for (name in interface.prototype) {
            if (name === "constructor") {
                continue;
            }
            //接口方法
            if (typeof interface.prototype[name] === "function") {
                if (_noMethodForInterface(children, name) && _noMethodForInterface(parentClass.prototype, name)) {
                    throw new Error("Interface method '" + name + "' must be overwrited!");
                }
            }
                //接口屬性
            else {
                if (_noAttritubeForInterface(children, name) && _noAttritubeForInterface(parentClass.prototype, name)) {
                    throw new Error("Interface attribute '" + name + "' must be overwrited!");
                }
            }
        }
    };
    function _noMethodForAbstract(_class, name) {
        return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
    };
    function _noAttritubeForAbstract(_class, name) {
        return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
    };
    function _noMethodForInterface(_class, name) {
        return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
    };
    function _noAttritubeForInterface(_class, name) {
        return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
    };

    function AClass(){
    };

    function Class(){
    };

    YYC.AClass = AClass;
    YYC.Class = Class;
}());
View Code

將AClass中的每一個職責提取為一個內部函數,然后再在AClass中調用這些內部函數:

//創建抽象類
//抽象類能夠繼承接口、抽象類以及實體類,但此處約定抽象類只能繼承接口和抽象類,不能繼承實體類!
//(這樣方便判斷抽象類是否包含全部的父類(接口/抽象類)成員)

function AClass(_parent, _prop) {

    var name = null, temp = {};
    var parentClass = null,
            interface = null,
        prop = null;

    ////原型恢復標志,用於防止第一次創建實例時恢復原型
    //var mark_resume = false;

    function _getByParent() {
        //if (arguments.length === 1) {
        if (_prop === undefined) {
            prop = _parent;
            parentClass = null;
            interface = null;
        }
        else if (typeof _parent === "object") {

            if (!_parent.Class && !_parent.Interface) {
                throw new Error("Please add AbstractClass or Interface!");
            }
            if (_getFunctionName(_parent.Class) === "F" || _getFunctionName(_parent.Interface) === "F") {
                throw new Error("AbstractClass here can't inherit parentClass which is created by Class function!");
            }

            parentClass = _parent.Class;
            interface = _parent.Interface;

            prop = _prop;
        }
            //_parent直接為xx,就表示父類為抽象類
        else if (typeof _parent === "function") {
            if (_getFunctionName(_parent) === "F") {
                throw new Error("AbstractClass here can't inherit parentClass which is created by Class function!");
            }

            parentClass = _parent;
            interface = null;

            prop = _prop;
        }
        else {
            throw new Error("arguments is not allowed!");
        }
    };
    function _prepareAndAddPublic() {
        if (prop.Public) {
            for (name in prop.Public) {
                if (prop.Public.hasOwnProperty(name)) {
                    if (_prepareCheck("Public") === "continue") {
                        continue;
                    }
                    _addPublic();
                }
            }
        }
    };
    function _addPublic() {
        if (parentClass &&
            typeof prop.Public[name] === "function" &&
            typeof A.prototype[name] === "function") {
            A.prototype[name] = function (name) {
                return function () {
                    /*
                    //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                    this.baseToParrent = function () {
                        //這個寫法也可以!為什么不用apply修正this也行??!
                        //parentClass.prototype[name](); 

                        //此處的arguments為baseToParrent方法傳入的形參
                        //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                        return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                    };
                    */
                    //指向子類,可以用於模版模式
                    this.base = parentClass.prototype[name];

                    //執行fn並返回執行的結果
                    //此處的arguments為F.prototype[name]方法傳入的形參。
                    return prop.Public[name].apply(this, arguments);
                };

            }(name);
        }
        else {
            A.prototype[name] = prop.Public[name];
        }
    }
    function _prepareAndAddProtected() {
        if (prop.Protected) {
            for (name in prop.Protected) {
                if (prop.Protected.hasOwnProperty(name)) {
                    if (_prepareCheck("Protected") === "continue") {
                        continue;
                    }
                    A.prototype[name] = prop.Protected[name];

                }
            }
        }
    };
    function _prepareCheck(where) {
        //檢查抽象成員,抽象成員放到Public或Protected中
        if (name === "Abstract") {
            _addAbstract(prop[where][name], A, temp);
            return "continue";
        }
        //檢查虛方法,虛方法放到Public或Protected中
        if (name === "Virtual") {
            _addVirtual(prop[where][name], A, temp);
            return "continue";
        }
        //密封的方法(不允許子類重寫)
        if (name === "Sealed") {
            _addSealed(prop[where][name], A, temp);
            return "continue";
        }

        temp[name] = prop[where][name];    //用於檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
        return null;
    };

    // 本次調用所創建的類(構造函數)
    function A() {
    }


    //取出父類、接口
    _getByParent();

    // 如果此接口需要從其它接口擴展
    if (parentClass) {
        _inherit(A, parentClass);
    }

    //加入構造函數
    //抽象類本身因為不能實例化,所以不調用構造函數。
    //抽象類中的構造函數供子類構造函數中調用。
    _addInit(A, parentClass, prop);

    _addPrivate(A, prop.Private);

    _prepareAndAddPublic();


    //保護成員
    _prepareAndAddProtected();

    //放到外面的抽象成員,默認為公有抽象成員
    _addAbstract(prop.Abstract, A, temp);

    _addStatic(A, prop);

    //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的接口方法/屬性
    _check(null, interface, temp);

    return A;
};
View Code

同理Class重構為:

//創建普通類
//父類_parent可以為{Class: xx, Interface: xx},或者直接為xx類

function Class(_parent, _prop) {
    //當前是否處於創建類的階段。
    var initializing = false;
    var name = null;
    var parentClass = null, interface = null, prop = null, temp = {};
    //原型恢復標志,用於防止第一次創建實例時恢復原型
    var mark_resume = false;

    function _getByParent() {
        if (_prop === undefined) {
            prop = _parent;
            parentClass = null;
            interface = null;
        }
            //{Class: xx, Interface: xx}
        else if (typeof _parent === "object") {
            if (!_parent.Class && !_parent.Interface) {
                throw new Error("Please add Class or Interface!");
            }

            parentClass = _parent.Class;
            interface = _parent.Interface;
            prop = _prop;
        }
            //直接為xx類
        else if (typeof _parent === "function") {
            parentClass = _parent;
            interface = null;
            prop = _prop;
        }
        else {
            throw new Error("arguments is not allowed!");
        }
    };
    function _addParentSealed() {
        for (name in parentClass.prototype) {
            if (parentClass.prototype.hasOwnProperty(name)) {
                //如果不是抽象方法/保護方法/私有方法/接口成員,則加入到temp中。
                //用於添加父類的密封方法(因為子類並沒有加入父類的密封方法)。
                if (!name.match(/^Abstract_/) || !name.match(/^P_/) || !name.match(/^_/) || !name.match(/^Interface_/)) {
                    temp[name] = parentClass.prototype[name];
                }
            }
        }
    };
    function _prepareAndAddPublic() {
        if (prop.Public) {
            for (name in prop.Public) {
                if (prop.Public.hasOwnProperty(name)) {
                    if (_prepareCheck("Public") === "continue") {
                        continue;
                    }
                    _addPublic();
                }
            }
        }
    };
    function _addPublic() {
        // 如果此類繼承自父類parent並且父類原型中存在同名函數name
        if (parentClass &&
typeof prop.Public[name] === "function" &&
typeof F.prototype[name] === "function") {
            F.prototype[name] = function (name) {
                return function () {
                    //指向子類,可以用於模版模式
                    this.base = parentClass.prototype[name];
                    //執行fn並返回執行的結果
                    //此處的arguments為F.prototype[name]方法傳入的形參。
                    return prop.Public[name].apply(this, arguments);
                };
            }(name);

        }
        else {
            F.prototype[name] = prop.Public[name];
        }
    }
    function _prepareAndAddProtected() {
        if (prop.Protected) {
            for (name in prop.Protected) {
                if (prop.Protected.hasOwnProperty(name)) {
                    if (_prepareCheck("Protected") === "continue") {
                        continue;
                    }
                    F.prototype[name] = prop.Protected[name];

                }
            }
        }
    };
    function _prepareCheck(where) {
        //檢查虛方法,虛方法放到Public或Protected中
        if (name === "Virtual") {
            _addVirtual(prop[where][name], A, temp);
            return "continue";
        }
        //密封的方法(不允許子類重寫)
        if (name === "Sealed") {
            _addSealed(prop[where][name], A, temp);
            return "continue";
        }

        temp[name] = prop[where][name];    //用於檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
        return null;
    };

    _getByParent();

    // 本次調用所創建的類(構造函數)
    function F() {
        //防止第一次創建實例時恢復原型
        if (mark_resume) {
            //還原原型
            _extendDeep(F.backUp_prototype, F.prototype);
        }
        else {
            mark_resume = true;
        }

        // 如果當前處於實例化類的階段,則調用Init原型函數
        if (!initializing) {
            this.Init && this.Init.apply(this, arguments);
        }
        /*不能刪除私有成員和保護成員!否則類的成員就不能調用到私有和保護的成員了(因為已經刪除了)!
        對象的創建算法參考http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html




        //刪除私有成員和保護成員,這樣外界就不能訪問私有和保護成員了!
        for (name in this) {
        if (name.search(/(^_)|(^P_)/) !== -1) {
        delete F.prototype[name];
        //                                                    this[name] = null;
        }
          
        }
        */
    }

    // 如果此類需要從其它類擴展
    if (parentClass) {
        initializing = true;
        _inherit(F, parentClass);
        initializing = false;
    }

    _addInit(F, parentClass, prop);

    if (parentClass) {
        _addParentSealed();
    }

    _addPrivate(F, prop.Private);

    //保護成員
    _prepareAndAddProtected();

    if (prop.Abstract) {
        throw new Error("Only abstractClass can have abstract methods!");
    }

    _prepareAndAddPublic();

    //檢查公有成員和虛函數是否實現了抽象方法/屬性 或 接口方法/屬性
    _check(parentClass, interface, temp);

    _addStatic(F, prop);


    //備份原型
    F.backUp_prototype = _extendDeep(F.prototype);

    return F;
};
View Code

重命名temp

AClass和Class中的局部屬性temp的職責是存儲該類成員的名稱,從而用於檢查該類成員是否實現了接口或者父類的抽象成員。

因此,將temp改名為children,這樣能反映職責。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM