1 
  2 /**
  3  * @namespace Class是提供类的创建的辅助工具。
  4  * @static
  5  * @module hilo/core/Class
  6  */
  7 var Class = (function(){
  8 
  9 /**
 10  * 此方法是在Hilo中创建类的主要方法。
 11  * @param {Object} properties 要创建的类的相关属性和方法。主要有:
 12  * <ul>
 13  * <li><b>Extends</b> - 指定要继承的父类。</li>
 14  * <li><b>Mixes</b> - 指定要混入的成员集合对象。</li>
 15  * <li><b>Statics</b> - 指定类的静态属性或方法。</li>
 16  * </ul>
 17  * @returns {Object} 创建好的类。
 18  */
 19 var create = function(properties){
 20     properties = properties || {};
 21     var clazz = properties.hasOwnProperty('constructor') ? properties.constructor : function(){};
 22     implement.call(clazz, properties);
 23     return clazz;
 24 }
 25 
 26 /**
 27  * @private
 28  */
 29 var implement = function(properties){
 30     var proto = {}, key, value;
 31     for(key in properties){
 32         value = properties[key];
 33         if(classMutators.hasOwnProperty(key)){
 34             classMutators[key].call(this, value);
 35         }else{
 36             proto[key] = value;
 37         }
 38     }
 39 
 40     mix(this.prototype, proto);
 41 };
 42 
 43 var classMutators = /** @ignore */{
 44     Extends: function(parent){
 45         var existed = this.prototype, proto = createProto(parent.prototype);
 46         //inherit static properites
 47         mix(this, parent);
 48         //keep existed properties
 49         mix(proto, existed);
 50         //correct constructor
 51         proto.constructor = this;
 52         //prototype chaining
 53         this.prototype = proto;
 54         //shortcut to parent's prototype
 55         this.superclass = parent.prototype;
 56     },
 57 
 58     Mixes: function(items){
 59         items instanceof Array || (items = [items]);
 60         var proto = this.prototype, item;
 61 
 62         while(item = items.shift()){
 63             mix(proto, item.prototype || item);
 64         }
 65     },
 66 
 67     Statics: function(properties){
 68         mix(this, properties);
 69     }
 70 };
 71 
 72 /**
 73  * @private
 74  */
 75 var createProto = (function(){
 76     if(Object.__proto__){
 77         return function(proto){
 78             return {__proto__: proto};
 79         }
 80     }else{
 81         var Ctor = function(){};
 82         return function(proto){
 83             Ctor.prototype = proto;
 84             return new Ctor();
 85         }
 86     }
 87 })();
 88 
 89 /**
 90  * 混入属性或方法。
 91  * @param {Object} target 混入目标对象。
 92  * @returns {Object} 混入目标对象。
 93  */
 94 var mix = function(target){
 95     for(var i = 1, len = arguments.length; i < len; i++){
 96         var source  = arguments[i], defineProps;
 97         for(var key in source){
 98             var prop = source[key];
 99             if(prop && typeof prop === 'object'){
100                 if(prop.value !== undefined || typeof prop.get === 'function' || typeof prop.set === 'function'){
101                     defineProps = defineProps || {};
102                     defineProps[key] = prop;
103                     continue;
104                 }
105             }
106             target[key] = prop;
107         }
108         if(defineProps) defineProperties(target, defineProps);
109     }
110 
111     return target;
112 };
113 
114 try{
115     var defineProperty = Object.defineProperty, 
116         defineProperties = Object.defineProperties;
117     defineProperty({}, '$', {value:0});
118 }catch(e){
119     if('__defineGetter__' in Object){
120         defineProperty = function(obj, prop, desc){
121             if('value' in desc) obj[prop] = desc.value;
122             if('get' in desc) obj.__defineGetter__(prop, desc.get);
123             if('set' in desc) obj.__defineSetter__(prop, desc.set);
124             return obj;
125         };
126         defineProperties = function(obj, props){
127             for(var prop in props){
128                 if(props.hasOwnProperty(prop)){
129                     defineProperty(obj, prop, props[prop]);
130                 }
131             }
132             return obj;
133         };
134     }
135 }
136 
137 return {create:create, mix:mix};
138 
139 })();
140