<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head><title>JavaScript Class</title></head>
<body>
<script type="text/javascript">
function class_ (cls) {
if (Object.prototype.toString.call(cls) !== '[object Function]') {throw new Error('Class constructor must be a function.');}
return cls();
}
function extend_ (child, parent) {
var key;
function F () {}
if (Object.prototype.toString.call(child) === '[object Object]' && Object.prototype.toString.call(parent) === '[object Object]') {
for (key in parent) {if (parent.hasOwnProperty(key)) {child[key] = parent[key];}}
return;
}
if (Object.prototype.toString.call(child) === '[object Function]' && Object.prototype.toString.call(parent) === '[object Object]') {
child.prototype = parent;
child.prototype.constructor = child;
child.super_ = parent;
}
if (Object.prototype.toString.call(child) === '[object Function]' && Object.prototype.toString.call(parent) === '[object Function]') {
for (key in parent) {if (parent.hasOwnProperty(key)) {child[key] = parent[key];}}
F.prototype = parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
child.super_ = parent.prototype;
}
}
function mixin_ (child) {
var mixins = Array.prototype.slice.call(arguments, 1)
, i, key, len = mixins.length;
if (len) {
for (i = 0; i < len; i++) {
for (key in mixins[i]) {if (mixins[i].hasOwnProperty(key)) {child[key] = mixins[i][key];}}
for (key in mixins[i].prototype) {child.prototype[key] = mixins[i].prototype[key];}
}
}
}
function singleton_() {return {for_: function (cls) {cls.instance_ = undefined;}}}
function create_singleton_ (cls) {
if (cls.instance_ !== undefined) {return cls.instance_;} else {return cls.instance_ = new cls();}
}
function constructor_ (func) {return {for_: function (cls) {cls.new_ = func;}}}
function destructor_ (func) {return {for_: function (cls) {cls.prototype.destroy_ = func;}}}
function default_ (propName, propValue) {return {for_: function (cls) {cls.prototype[propName] = propValue;}}}
function public_ (propName, propValue) {return {for_: function (cls) {cls.prototype[propName] = propValue;}}}
function private_ (propName, propValue) {return {for_: function (cls) {
if (propName.substring(0, 1) !== '_') {throw new Error('Private property name must starts from symbol "_".');}
cls.prototype[propName] = propValue;
}}
}
function override_ (propName, propValue) {return {for_: function (cls) {cls.prototype[propName] = propValue;}}}
function final_ (propName, propValue) {return {for_: function (cls) {cls.prototype[propName] = propValue;}}}
function static_ (propName, propValue) {return {for_: function (cls) {cls[propName] = propValue;}}}
function implementation_ (cls, propArray) {
for (var i = 0, len = propArray.length; i < len; i++) {propArray[i].for_(cls);}
}
function interface_ (intfc) {
if (Object.prototype.toString.call(intfc) !== '[object Function]') {throw new Error('Interface constructor must be a function.');}
return intfc();
}
function impliment_(cls, intfc) {
var key, errorMessage = 'Class does not implement the interface correctly for "';
for (key in intfc) {if (!(key in cls)) {throw new Error(errorMessage + key + '".');}}
for (key in intfc.prototype) {if (!(key in cls.prototype)) {throw new Error(errorMessage + key + '".');}}
}
var AbstractClass = class_(function(){
function AbstractClass () {}
implementation_(AbstractClass, [
constructor_(function () {var instance = new AbstractClass(); return instance;})
, destructor_(function () {})
]);
AbstractClass.super_ = Object.prototype;
return AbstractClass;
});
var ParentClass = class_(function(){
function ParentClass () {}
extend_(ParentClass, AbstractClass);
implementation_(ParentClass, [
constructor_(function (initVar) {
var instance = new ParentClass();
instance.initVar = initVar;
var privateVar = 'ParentClass private var';
function privateFunction () {return 'ParentClass private function can show ' + privateVar + ' and ' + instance._privateMethod();}
instance.eventFunction = function () {alert(privateFunction());}
document.addEventListener('click', instance.eventFunction, false);
return instance;
})
, destructor_(function () {
document.removeEventListener('click', this.eventFunction, false);
console.log('ParentClass destroyed.');
})
, default_('defaultVar', 'ParentClass default var.')
, public_('publicMethod', function () {return 'ParentClass public method.';})
, private_('_privateMethod', function () {return 'ParentClass private method.';})
, final_('finalMethod', function () {return 'ParentClass final method.';})
, static_('staticMethod', function () {return 'ParentClass static method.';})
]);
return ParentClass;
});
var parentObject = ParentClass.new_('ParentClass init var');
console.log(parentObject.constructor.name);
console.log(parentObject.defaultVar);
console.log(parentObject.initVar);
console.log(parentObject.publicMethod());
console.log(parentObject.finalMethod());
console.log(ParentClass.staticMethod());
setTimeout(function(){parentObject.destroy_(); parentObject = null;}, 5000);
console.log('----------------------------------------');
var MixinClass = class_(function(){
function MixinClass () {}
implementation_(MixinClass, [
public_('mixinPublicMethod', function () {return 'MixinClass public method.';})
, static_('mixinStaticMethod', function () {return 'MixinClass static method.';})
]);
return MixinClass;
});
var ChildClass = class_(function(){
function ChildClass () {}
extend_(ChildClass, ParentClass);
implementation_(ChildClass, [
constructor_(function (initVar) {
var instance = new ChildClass();
instance.initVar = initVar;
return instance;
})
, destructor_(function () {console.log('ChildClass destroyed.');})
, override_('publicMethod', function () {return 'ChildClass public method.';})
]);
mixin_(ChildClass, MixinClass);
return ChildClass;
});
var childObject = ChildClass.new_('ChildClass init var');
console.log(childObject.constructor.name);
console.log(childObject.defaultVar);
console.log(childObject.initVar);
console.log(childObject.publicMethod());
console.log(childObject.finalMethod());
console.log(ChildClass.staticMethod());
console.log(childObject.mixinPublicMethod());
console.log(ChildClass.mixinStaticMethod());
setTimeout(function(){childObject.destroy_(); childObject = null;}, 5000);
console.log('----------------------------------------');
var SingletonClassInterface = interface_(function(){
function SingletonClassInterface () {}
implementation_(SingletonClassInterface, [
singleton_()
, constructor_()
, destructor_()
, default_('defaultVar')
, public_('publicMethod')
, private_('_privateMethod')
, final_('finalMethod')
, static_('staticMethod')
, public_('mixinPublicMethod')
, static_('mixinStaticMethod')
]);
return SingletonClassInterface;
});
var SingletonClass = class_(function(){
function SingletonClass () {}
extend_(SingletonClass, ChildClass);
implementation_(SingletonClass, [
singleton_()
, constructor_(function (initVar) {
if (SingletonClass.instance_) {return SingletonClass.instance_;}
var instance = create_singleton_(SingletonClass);
instance.initVar = initVar;
return instance;
})
, destructor_(function () {console.log('SingletonClass destroyed.');})
]);
impliment_(SingletonClass, SingletonClassInterface);
return SingletonClass;
});
var singletonObject1 = SingletonClass.new_('SingletonClass init var 1');
var singletonObject2 = SingletonClass.new_('SingletonClass init var 2');
console.log('Is singleton? ' + (singletonObject1 === singletonObject2));
console.log(singletonObject1.constructor.name);
console.log(singletonObject1.defaultVar);
console.log(singletonObject1.initVar);
console.log(singletonObject1.publicMethod());
console.log(singletonObject1.finalMethod());
console.log(SingletonClass.staticMethod());
console.log(singletonObject1.mixinPublicMethod());
console.log(SingletonClass.mixinStaticMethod());
setTimeout(function(){singletonObject1.destroy_(); singletonObject1 = null; singletonObject2 = null;}, 5000);
console.log('----------------------------------------');
function Enum () {
var i, len = arguments.length, allValues;
for (i = 0; i < len; i++) {
this[arguments[i]] = i;
}
this.allValues = Array.prototype.slice.call(arguments);
}
Enum.prototype.values = function () {
return this.allValues;
};
var Color = new Enum('RED', 'GREEN', 'BLUE');
console.log(Color.RED);
console.log(Color.GREEN);
console.log(Color.BLUE);
console.log(Color.values());
console.log('----------------------------------------');
function class_2 (cls) {
var classFunction;
function AbstractClass () {}
AbstractClass.new_ = function () {var instance = new AbstractClass(); return instance;};
AbstractClass.prototype.destroy = function () {};
AbstractClass.super_ = Object.prototype;
if (cls && cls.name_ && cls.body_) {
classFunction = (new Function('return function ' + cls.name_ + ' () {}'))();
if (cls.extends_) {extend_(classFunction, cls.extends_);} else {extend_(classFunction, AbstractClass);}
implementation_(classFunction, cls.body_);
if (cls.mixin_) {mixin_(classFunction, cls.mixin_);}
if (cls.impements_) {impliment_(classFunction, cls.impements_);}
return classFunction;
} else {
throw new Error('Class name and body must be specified.');
}
}
function interface_2 (intfc) {
return class_2(intfc);
}
var SingletonClassInterface2 = interface_2({
name_: 'SingletonClassInterface2'
, extends_: SingletonClassInterface
, body_: [
singleton_()
, constructor_()
, destructor_()
, default_('defaultVar')
, public_('publicMethod')
, private_('_privateMethod')
, final_('finalMethod')
, static_('staticMethod')
, public_('mixinPublicMethod')
, static_('mixinStaticMethod')
]
});
var ParentClass2 = class_2({
name_: 'ParentClass2'
, extends_: ParentClass
, impements_: SingletonClassInterface2
, mixin_: MixinClass
, body_: [
singleton_()
, constructor_(function (initVar) {
if (ParentClass2.instance_) {return ParentClass2.instance_;}
var instance = create_singleton_(ParentClass2);
instance.initVar = initVar;
return instance;
})
, destructor_(function () {console.log('ParentClass2 destroyed.');})
, override_('publicMethod', function () {return 'ParentClass2 public method.';})
]
});
var singletonParentObject21 = ParentClass2.new_('Singleton ParentClass2 init var 1');
var singletonParentObject22 = ParentClass2.new_('Singleton ParentClass2 init var 2');
console.log('Is singleton? ' + (singletonParentObject21 === singletonParentObject22));
console.log(singletonParentObject21.constructor.name);
console.log(singletonParentObject21.defaultVar);
console.log(singletonParentObject21.initVar);
console.log(singletonParentObject21.publicMethod());
console.log(singletonParentObject21.finalMethod());
console.log(ParentClass2.staticMethod());
console.log(singletonParentObject21.mixinPublicMethod());
console.log(ParentClass2.mixinStaticMethod());
setTimeout(function(){singletonParentObject21.destroy_(); singletonParentObject21 = null; singletonParentObject22 = null;}, 5000);
console.log('----------------------------------------');
function ClassicalClass (initVar) {
this.initVar = initVar;
}
ClassicalClass.staticMethod = function () {return 'ClassicalClass static method.';};
ClassicalClass.prototype = {
defaultVar: 'ClassicalClass default var.'
, publicMethod: function () {return 'ClassicalClass public method.';}
, _privateMethod: function () {return 'ClassicalClass private function can show ' + this.initVar;}
, destroy: function () {console.log('ClassicalClass destroyed.');}
, constructor: ClassicalClass
}
var classicalObject = new ClassicalClass('ClassicalClass init var.');
console.log(classicalObject.constructor.name);
console.log(classicalObject.defaultVar);
console.log(classicalObject.initVar);
console.log(classicalObject.publicMethod());
console.log(classicalObject._privateMethod());
console.log(ClassicalClass.staticMethod());
setTimeout(function(){classicalObject.destroy(); classicalObject = null;}, 5000);
console.log('----------------------------------------');
</script>
</body>
</html>
Комментариев нет:
Отправить комментарий