1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * 创建类示例: 9 * <pre> 10 * var Bird = Hilo.Class.create({ 11 * Extends: Animal, 12 * Mixes: EventMixin, 13 * constructor: function(name){ 14 * this.name = name; 15 * }, 16 * fly: function(){ 17 * console.log('I am flying'); 18 * }, 19 * Statics: { 20 * isBird: function(bird){ 21 * return bird instanceof Bird; 22 * } 23 * } 24 * }); 25 * 26 * var swallow = new Bird('swallow'); 27 * swallow.fly(); 28 * Bird.isBird(swallow); 29 * </pre> 30 * @namespace Class是提供类的创建的辅助工具。 31 * @static 32 * @module hilo/core/Class 33 */ 34 var Class = (function(){ 35 36 /** 37 * 根据参数指定的属性和方法创建类。 38 * @param {Object} properties 要创建的类的相关属性和方法。主要有: 39 * <ul> 40 * <li><b>Extends</b> - 指定要继承的父类。</li> 41 * <li><b>Mixes</b> - 指定要混入的成员集合对象。</li> 42 * <li><b>Statics</b> - 指定类的静态属性或方法。</li> 43 * <li><b>constructor</b> - 指定类的构造函数。</li> 44 * <li>其他创建类的成员属性或方法。</li> 45 * </ul> 46 * @returns {Object} 创建的类。 47 */ 48 var create = function(properties){ 49 properties = properties || {}; 50 var clazz = properties.hasOwnProperty('constructor') ? properties.constructor : function(){}; 51 implement.call(clazz, properties); 52 return clazz; 53 }; 54 55 /** 56 * @private 57 */ 58 var implement = function(properties){ 59 var proto = {}, key, value; 60 for(key in properties){ 61 value = properties[key]; 62 if(classMutators.hasOwnProperty(key)){ 63 classMutators[key].call(this, value); 64 }else{ 65 proto[key] = value; 66 } 67 } 68 69 mix(this.prototype, proto); 70 }; 71 72 var classMutators = /** @ignore */{ 73 Extends: function(parent){ 74 var existed = this.prototype, proto = createProto(parent.prototype); 75 //inherit static properites 76 mix(this, parent); 77 //keep existed properties 78 mix(proto, existed); 79 //correct constructor 80 proto.constructor = this; 81 //prototype chaining 82 this.prototype = proto; 83 //shortcut to parent's prototype 84 this.superclass = parent.prototype; 85 }, 86 87 Mixes: function(items){ 88 items instanceof Array || (items = [items]); 89 var proto = this.prototype, item; 90 91 while(item = items.shift()){ 92 mix(proto, item.prototype || item); 93 } 94 }, 95 96 Statics: function(properties){ 97 mix(this, properties); 98 } 99 }; 100 101 /** 102 * @private 103 */ 104 var createProto = (function(){ 105 if(Object.__proto__){ 106 return function(proto){ 107 return {__proto__: proto}; 108 }; 109 }else{ 110 var Ctor = function(){}; 111 return function(proto){ 112 Ctor.prototype = proto; 113 return new Ctor(); 114 }; 115 } 116 })(); 117 118 /** 119 * 混入属性或方法。 120 * @param {Object} target 混入目标对象。 121 * @param {Object} source 要混入的属性和方法来源。可支持多个来源参数。 122 * @returns {Object} 混入目标对象。 123 */ 124 var mix = function(target){ 125 for(var i = 1, len = arguments.length; i < len; i++){ 126 var source = arguments[i], defineProps; 127 for(var key in source){ 128 var prop = source[key]; 129 if(prop && typeof prop === 'object'){ 130 if(prop.value !== undefined || typeof prop.get === 'function' || typeof prop.set === 'function'){ 131 defineProps = defineProps || {}; 132 defineProps[key] = prop; 133 continue; 134 } 135 } 136 target[key] = prop; 137 } 138 if(defineProps) defineProperties(target, defineProps); 139 } 140 141 return target; 142 }; 143 144 var defineProperty, defineProperties; 145 try{ 146 defineProperty = Object.defineProperty; 147 defineProperties = Object.defineProperties; 148 defineProperty({}, '$', {value:0}); 149 }catch(e){ 150 if('__defineGetter__' in Object){ 151 defineProperty = function(obj, prop, desc){ 152 if('value' in desc) obj[prop] = desc.value; 153 if('get' in desc) obj.__defineGetter__(prop, desc.get); 154 if('set' in desc) obj.__defineSetter__(prop, desc.set); 155 return obj; 156 }; 157 defineProperties = function(obj, props){ 158 for(var prop in props){ 159 if(props.hasOwnProperty(prop)){ 160 defineProperty(obj, prop, props[prop]); 161 } 162 } 163 return obj; 164 }; 165 } 166 } 167 168 return {create:create, mix:mix}; 169 170 })(); 171