Javascript OOP框架YOOP重构实践(上) Wonder

大家好!今天跟大家一起分享我的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,这样能反映职责。

原文地址:https://www.cnblogs.com/chaogex/p/3125776.html