Hilo/docs/api-en/code/core/Class.js
2016-12-14 14:40:55 +08:00

171 lines
4.6 KiB
JavaScript

/**
* Hilo
* Copyright 2015 alibaba.com
* Licensed under the MIT License
*/
/**
* Create Example Class:
* <pre>
* var Bird = Hilo.Class.create({
* Extends: Animal,
* Mixes: EventMixin,
* constructor: function(name){
* this.name = name;
* },
* fly: function(){
* console.log('I am flying');
* },
* Statics: {
* isBird: function(bird){
* return bird instanceof Bird;
* }
* }
* });
*
* var swallow = new Bird('swallow');
* swallow.fly();
* Bird.isBird(swallow);
* </pre>
* @namespace Class Class is created to aid the developer.
* @static
* @module hilo/core/Class
*/
var Class = (function(){
/**
* Create a class based on the parameters, properties and methods specified.
* @param {Object} properties Properties and methods to create the class.
* <ul>
* <li><b>Extends</b> - Designed to inherit the parent class.</li>
* <li><b>Mixes</b> - Specifies mixed member collection object.</li>
* <li><b>Statics</b> - Static property or method specified class.</li>
* <li><b>constructor</b> - The constructor of specified class.</li>
* <li>Other members of the property or method to create the class.</li>
* </ul>
* @returns {Object} Create classes.
*/
var create = function(properties){
properties = properties || {};
var clazz = properties.hasOwnProperty('constructor') ? properties.constructor : function(){};
implement.call(clazz, properties);
return clazz;
};
/**
* @private
*/
var implement = function(properties){
var proto = {}, key, value;
for(key in properties){
value = properties[key];
if(classMutators.hasOwnProperty(key)){
classMutators[key].call(this, value);
}else{
proto[key] = value;
}
}
mix(this.prototype, proto);
};
var classMutators = /** @ignore */{
Extends: function(parent){
var existed = this.prototype, proto = createProto(parent.prototype);
//inherit static properites
mix(this, parent);
//keep existed properties
mix(proto, existed);
//correct constructor
proto.constructor = this;
//prototype chaining
this.prototype = proto;
//shortcut to parent's prototype
this.superclass = parent.prototype;
},
Mixes: function(items){
items instanceof Array || (items = [items]);
var proto = this.prototype, item;
while(item = items.shift()){
mix(proto, item.prototype || item);
}
},
Statics: function(properties){
mix(this, properties);
}
};
/**
* @private
*/
var createProto = (function(){
if(Object.__proto__){
return function(proto){
return {__proto__: proto};
};
}else{
var Ctor = function(){};
return function(proto){
Ctor.prototype = proto;
return new Ctor();
};
}
})();
/**
* Mixed property or method.
* @param {Object} target Mixed audiences.
* @param {Object} source The source whose methods and properties are to be mixed. It can support multiple source parameters.
* @returns {Object} Mixed audiences.
*/
var mix = function(target){
for(var i = 1, len = arguments.length; i < len; i++){
var source = arguments[i], defineProps;
for(var key in source){
var prop = source[key];
if(prop && typeof prop === 'object'){
if(prop.value !== undefined || typeof prop.get === 'function' || typeof prop.set === 'function'){
defineProps = defineProps || {};
defineProps[key] = prop;
continue;
}
}
target[key] = prop;
}
if(defineProps) defineProperties(target, defineProps);
}
return target;
};
var defineProperty, defineProperties;
try{
defineProperty = Object.defineProperty;
defineProperties = Object.defineProperties;
defineProperty({}, '$', {value:0});
}catch(e){
if('__defineGetter__' in Object){
defineProperty = function(obj, prop, desc){
if('value' in desc) obj[prop] = desc.value;
if('get' in desc) obj.__defineGetter__(prop, desc.get);
if('set' in desc) obj.__defineSetter__(prop, desc.set);
return obj;
};
defineProperties = function(obj, props){
for(var prop in props){
if(props.hasOwnProperty(prop)){
defineProperty(obj, prop, props[prop]);
}
}
return obj;
};
}
}
return {create:create, mix:mix};
})();