当前位置: 代码迷 >> JavaScript >> 发个JS练手作品,简单的OO封装解决思路
  详细解决方案

发个JS练手作品,简单的OO封装解决思路

热度:132   发布时间:2012-05-03 14:06:56.0
发个JS练手作品,简单的OO封装
最近翻书复习了下基础知识,感觉书上的面向对象的例子用起来不是很顺手
所以自己改了下,纯粹练手,有意见的请拍砖,当然最好能给出更好的例子。
JScript code
var $class = (function(){       
        var guid = 0,
        classMap  = {},
        caller    = null,
        callStack = [];
       
        return {
                create : createClass
        }
       
        //------------------------[辅助函数部分]------------------------
   
    /**
    * 创建新类.
    * @param  {constructor}superClass   超类构造器,该类必须由$class.create创建
    * @param  {Json}proto               类原型
    * @return {constructor}
    */
        function createClass(superClass, proto){
        var isSuperValid =  superClass instanceof Function
                         && superClass.prototype
                         && superClass.prototype.init instanceof Function;            
        
        superClass = isSuperValid ? superClass : null;
                  
                var superProto = superClass ? superClass.prototype : null;
                        
                //定义类构造函数
                var klass = function() {
                        var args = [].slice.call(arguments);
                       
                        //执行父类构造函数.
                        if(superClass){                                       
                                superClass.apply(this, args);
                        }
               
                        //若自己的原型中有init方法,执行init
                        if(klass.prototype.hasOwnProperty('init')){
                                klass.prototype.init.apply(this, args);
                        }       
                };
               
                //定义类原型
                var klassProto = getClassProto(superProto, proto);               
                klassProto.constructor = klass;
                klass.prototype = klassProto;
               
                //返回类
                return klass;
        }
       
    /**
    * 获取类原型.
    * @param  {json}superProto  超类原型
    * @param  {Json}overwrites  需要重写方法
    * @return {json}
    */
        function getClassProto(superProto, overwrites) {
                var i, F, proto, classId = getGuid();
               
                if(superProto){
                        F = function(){};
                        F.prototype = superProto;
                        proto = new F();
                }else{
                        proto = getDefaultProto();
                }
               
                //用overwrites中方法覆盖原型中的方法
                for(i in overwrites){
                        if(overwrites.hasOwnProperty(i)){
                                proto[i] = overwrites[i];
                        }       
                }
        
        //修复IE中for in不能遍历toString、valueOf等属性的Bug
        if(document.all){
            var len, method, methods = ['toString', 'valueOf'];
            for(i=0, len = methods.length; i < len; i++){
                method = methods[i];
                if( overwrites.hasOwnProperty(method) ){
                    proto[method] = overwrites[method];
                }
            }
        }        
               
                //注册类关系       
                proto.classId = classId;
                regClass(proto, superProto);
               
                //确保原型中含有必要的原型方法
                addMastHasMethods(proto);
               
                return proto;       
        }
       
    /**
    * 获取默认原型.
    * @return {json}
    */
        function getDefaultProto(){
                return {
                        init : function(){},                       
                        callSuper : callSuper
                };
        }
       
    /**
    * 调用超类方法.
    * @param  {String}methodName   方法名
    * @return
    */
        function callSuper(methodName){
                caller        = (caller === null ? this : caller);
               
                var curClsId = callStack.length > 0
                     ? callStack[callStack.length - 1]
                     : this.classId;
        
        var args   = [].slice.call(arguments, 1),
            parent = getParent(curClsId),
            ret;
            
                if(parent && parent[methodName]){
            callStack.push(parent.classId);
                       
            try{
                ret = parent[methodName].apply(caller, args);
            }catch(e){
                alert(e);
                        }
                       
                        callStack.pop();
                }

                //调用完毕后将调用上下文清空
                if(callStack.length === 0){
                        caller = null;
                }
        
        return ret;
        }
       
    /**
    * 将类信息注册到类记录表中.
    * @param {json}proto    类原型.
    * @param {json}parent   超类原型
    */
        function regClass(proto, superProto){
                var classId  = proto.classId;
               
                classMap[classId] = {
                        id    : classId,
                        proto : proto,
                        parent: superProto
                };               
        }               
       
    /**
    * 检查原型链中是否有必须要实现的方法,没有的话,向原型中添加.
    * @param {json}proto
    */
        function addMastHasMethods(proto){
                var i, dftProto = getDefaultProto();
                for(i in dftProto){
                        if(dftProto.hasOwnProperty(i) && !proto[i]){
                                proto[i] = dftProto[i];
                        }
                }
        }       
       
    /**
    * 获取guid.
    * @return {int}
    */
        function getGuid(){
                return guid++;
        }
       
    /**
    * 获取超类原型.
    * @param  {int}classId   类ID
    * @return {json}         超类原型, 若存在返回null.
    */
        function getParent(classId){
                var record = classMap[classId];
                return record ? record.parent : null;       
        }
})();

var Man = $class.create(null, {
    init : function(cfg){
        this.name = cfg.name;
        this.age  = cfg.age;  
    },
   
    say : function(){
        alert('my name is:' + this.name + ", " + this.age);
    },
   
    toString : function(){
        return (
             'name: ' + this.name
           + ', age: ' + this.age
        );
    }
});

var Student = $class.create(Man, {
    init : function(cfg){           //执行此方法前会自动调用Man.init
        this.stuNum = cfg.stuNum;
    },
   
    say : function(){
        this.callSuper('say');      //调用父类方法
        alert("i'm a student, my student number is " + this.stuNum);
    },
   
    toString : function(){
        return (
              this.callSuper('toString')
            + ', stuNum: ' + this.stuNum
        );        
    }
});

window.onload = function(){
    var m1 = new Man({name : '张三', age: 20}),
        s1 = new Student({
            name    : '王五',
            age     : 22,
            stuNum  : 'no-1'
        });
   
    m1.say();
    s1.say();   
    alert(m1.toString() + "\n" + s1.toString());
};
 
  相关解决方案