1.4.18 • Published 7 years ago

34rth-javascript-core-oo v1.4.18

Weekly downloads
32
License
MIT
Repository
github
Last release
7 years ago

Build Status npm npm

TABLE OF CONTENTS

GENERAL

JavaScript (node.js/browser) library for inheritance and mixins in JavaScript with strong coupling of contexts. Includes private/public/static members/functions as well as mixin architecture (borrowing functionality from mixins);

The package/framework is 100% stand-alone and is not dependant on any other npm packages. The packages listed in node_modules are exclusively for the performance comparison modules required to compare the baseline performances.

INSTALLATION

in Node.js

npm install 34rth-javascript-core-oo

in Browser

Download the /bin/oo.js file from github

<script type="text/javascript" src="oo.js"></script>

EXAMPLES

Classes (private/public variables/functions)

The example below shows the private, public functions/members, static functions and variables as well as the constructor. See example file.

var earth = require('34rth-javascript-core-oo');

var my_class = earth.core.object.extend(function(_super){
  this.__id__ = 'my_class'; //this is optional for debugging purpose; definition does not have to be included
  
  this.statics = {};//define the statics object:
  this.statics.my_static_function = function(){
    console.log('Hooray, I\'m static');
  };

  this.statics.my_other_static_function = function(){
    console.log('So what, so am I...');
  };

  this.statics.STATIC_VALUE = 'I am like a rock...';

  this.member_variable = 'I am a variable and can be accessed from any instance';

  var private_variable = 'I am shy';

  //I am the constructor, all your base are belong to us
  this.__init = function(a, b, c){
    console.log('Constructing is as easy as ' + a + ' ' + b + ' ' + c);
  };

  this.public_function = function(){
    console.log('total extrovert');
  };

  var private_function = function(){
    console.log('not really introvert, but do not really fancy being seen everywhere, anytime...');
  };
});

//testing the statics
my_class.my_static_function();
my_class.my_other_static_function();
console.log(my_class.STATIC_VALUE);

var my_instance = new my_class(1,2,3);
my_instance.public_function();
try{
  my_instance.private_function();
}catch(e){
  console.log('really, really, really don\'t want to be called');
}
console.log(my_instance.member_variable);
console.log(my_instance.private_variable);//undefined... they said they're shy :) 

Simple class inheritance and _super

Code example for simple inheritance calling _super constructor and methods. See example file.

var earth = require('34rth-javascript-core-oo');

//definition of bicycle class - extending from the core class
var bicycle = earth.core.object.extend(function(_super){
  this.__id__ = 'bicycle';//this is optional for debugging purposes and can be any random string

  // the bicycle class has three public member variables
  this.cadence = null;
  this.gear = null;
  this.speed = null;

  //constructor function
  this.__init = function(start_cadence, start_speed, start_gear){
    this.gear = start_gear;
    this.speed = start_speed;
    this.cadence = start_cadence;
  };

  this.set_cadence = function(value){
    this.cadence = value;
  };

  this.set_gear = function(value){
    this.gear = value;
  };

  this.apply_brake = function(decrement){
    this.speed -= decrement;
  };
 
  this.speed_up = function(increment){
    this.speed += increment;
  };

  this.get_speed = function(){
    return this.speed; 
  };
});

//definition of mountain_bike class, inheriting from the bicycle class
var mountain_bike = bicycle.extend(function(_super){
  this.__id__ = 'bicycle.mountain_bike';//this is optional for debugging purposes and can be any random string

  //the mountain_bike class adds one more public member variable
  this.seat_height = null;

  //constructor function
  this.__init = function(start_height, start_cadence, start_speed, start_gear){
    _super.__init.call(this, start_cadence, start_speed, start_gear);//call super prototype
    this.seat_height = start_height;
  };

  this.set_height = function(value){
    this.seat_height = value;
  };

	//we're shadowing the function speed_up of bicycle
	this.speed_up = function(increment){
		//on a mountainbike we're speeding up much faster
		this.speed += increment*1.2;
	};

  //we're shadowing the function get_speed of bicycle
  this.get_speed = function(){
    //but we're calling the function of the parent 
    return _super.get_speed.call(this);
  };
});

var bicycle_instance = new bicycle(1, 10, 1);
var mountain_bike_instance = new mountain_bike(90, 1, 10, 1);

console.log(bicycle_instance.speed);//prints 10 as speed of has not been modified
bicycle_instance.speed_up(15);//speeding up by 15 (e.g. m/h)
console.log(bicycle_instance.speed);//prints 25 as speed of has not been modified
console.log(typeof bicycle_instance);//returns object
console.log(bicycle_instance instanceof earth.core.object);//prints true
console.log(bicycle_instance instanceof bicycle);//prints true
console.log(bicycle_instance instanceof mountain_bike);//prints false
try{
	bicycle_instance.set_height(5);
}catch(e){
  console.log('Bicycle does not have a set_height function');
}


console.log(mountain_bike_instance.speed);//prints 10 as speed of has not been modified
mountain_bike_instance.speed_up(5);//speeding up by 5 (e.g. m/h)
console.log(mountain_bike_instance.speed);//prints 16 (10+5*1.2);
console.log(mountain_bike_instance.get_speed() == mountain_bike_instance.speed);//returns true as shadowed function get_speed calls parent function get_speed, returning the current speed
console.log(typeof bicycle_instance);//returns object
console.log(mountain_bike_instance instanceof earth.core.object);//prints true
console.log(mountain_bike_instance instanceof bicycle);//prints true
console.log(mountain_bike_instance instanceof mountain_bike);//prints true 

Static functions

Defining and calling static functions on classes. See example file.

var earth = require('34rth-javascript-core-oo');

var my_static_class = earth.core.object.extend(function(_super){
  this.statics = [];

  this.statics.say_hello = function(name){
    console.log('Hello ' + name);
  };
});

my_static_class.say_hello('Peter');//prints "Hello Peter"

Static functions and inheritance

Inheriting and calling inherited static functions. See example file.

var earth = require('34rth-javascript-core-oo');

var my_parent_static_class = earth.core.object.extend(function(_super){
  this.statics = [];

  this.statics.say_hello = function(name){
    console.log('Hello ' + name);
  };
});

var my_child_static_class = my_parent_static_class.extend(function(_super){
  this.statics = [];

  this.statics.say_bye = function(name){
    console.log('Bye ' + name);
  };
});

my_child_static_class.say_hello('Marry');//prints "Hello Marry"
my_child_static_class.say_bye('Peter');//prints "Bye Peter"
my_parent_static_class.say_hello('Peter');//print "Hello Peter"
try{
  my_parent_static_class.say_bye('Marry');//is not defined and throws an Exception
}catch(e){
  console.log('I am not defined');
}

Init Hooks

Init hooks allow to trigger any number of callback functions whenever a new instance of a class is created. Init hooks traverse the whole prototype chain (ie parent's init hooks will also get triggered). See example file.

var my_class = earth.core.object.extend(function(_super){
  this.__init = function(number){
    console.log('Yaaay, the constructor was just called');
    this.number = number;
  };
});

my_class.add_init_hook(function(_super){
  console.log('Class has been initialised with number ' + this.number);
});

new my_class(10);
//'Yaaay, the constructor was just called
//Class has been initialised with number 10

Init Hooks and _super

Init hooks also allow access to _super (always in context) so shadowed functions can be called. See example file.

var earth = require('34rth-javascript-core-oo');

var my_class = earth.core.object.extend(function(_super){
  this.__init = function(number){
    console.log('Yaaay, the constructor just was called');
    this.number = number;
  };

  this.my_special_function = function(){
    console.log('I am ' + this.number + ' times more special than anyone else!');
  };
});

var my_child_class = my_class.extend(function(_super){
  this.__init = function(number){
    _super.__init.call(this, number);
  };
  
  this.my_special_function = function(){
    console.log('Me toooooooo!');
  };
});

my_child_class.add_init_hook(function(_super){
  console.log('Class has been initialised with number ' + this.number);
  _super.my_special_function.call(this);
  this.my_special_function();
});

new my_child_class(10);
//Yaaay, the constructor just was called
//Class has been initialised with number 10
//I am 10 times more special than anyone else!
//Me toooooooo!

Mixins

Mixins can be used to implement functionality that can be shared between classes. As a class can only inherit from one other class (JAVA-style) mixins allow a way to reduce duplication of code (think aspect oriented programming in JAVA). See example file.

var earth = require('34rth-javascript-core-oo');

var speaker = earth.core.mixin.extend(function(_super){
  this.say_something = function(){
    console.log('something');
  };
});

//mixins can also inherit from other mixins
var hello = earth.core.mixin.extend(function(_super){
  this.say_hello = function(name){
    console.log('Hello ' + name);
  };
});

var bye = earth.core.mixin.extend(function(_super){
  this.say_goodbye = function(name){
    console.log('Bye ' + name);
  };
});

var app = earth.core.object.extend(function(_super){
  this.includes = [speaker, hello, bye];//array of mixins to include
});


var test = new app();

test.say_something();//Prints "Something"
test.say_hello('Marry');//prints "Hello Marry"
test.say_goodbye('Marry');//prints "Bye Marry"

Mixins and Inheritance

Mixins can also inherit functions (including full inheritance logic). See example file.

var earth = require('34rth-javascript-core-oo');

var speaker = earth.core.mixin.extend(function(_super){
  this.say_something = function(){
    console.log('something');
  };
});

//mixins can also inherit from other mixins
var speaker_with_good_memory = speaker.extend(function(_super){
  this.names = [];

  this.say_hello = function(name){
    this.names.push(name);
    console.log('Hello ' + this.names.join(', '));
  };
});

var app = earth.core.object.extend(function(_super){
  this.includes = [speaker, speaker_with_good_memory];//array of mixins to include
});


var test = new app();

test.say_something();//Prints "Something"
test.say_hello('Peter');//prints "Hello Peter"
test.say_hello('Marry');//prints "Hello Peter, Marry"
test.say_hello('Charly');//prints "Hello Peter, Marry, Charly"

Mixin and chaining

Trivially, all calls can be chained if desired, by returning this. See example file.

var earth = require('34rth-javascript-core-oo');

var speaker = earth.core.mixin.extend(function(_super){
  this.say_something = function(){
    console.log('something');
    return this;//returns a reference to the object mixing
  };
});

//mixins can also inherit from other mixins
var speaker_with_good_memory = speaker.extend(function(_super){
  this.names = [];

  this.say_hello = function(name){
    this.names.push(name);
    console.log('Hello ' + this.names.join(', '));
    return this;//returns a reference to the object mixing
  };
});

var app = earth.core.object.extend(function(_super){
  this.includes = [speaker, speaker_with_good_memory];//array of mixins to include
});


var test = new app();

test.say_something().say_hello('Peter').say_hello('Marry').say_hello('Charly');

Syntactic sugar (super calls in every class)

There is an in-built option to enable syntactic super sugar to have direct reference to super methods throughout the private/public class functions. Please note that the super sugar comes at a performance penalty of roughtly 40% compared to the results in the PERFORMANCE COMPARISON. The example below is the same as in Simple class inheritance and _super just with syntactic super sugar turned on.

Enabling the super sugar is done by passing the option {super:true} to the class definition as per the example file below.

var earth = require('34rth-javascript-core-oo');

//definition of bicycle class - extending from the core class
var bicycle = earth.core.object.extend(function(_super){
  this.__id__ = 'bicycle';//this is optional for debugging purposes and can be any random string

  // the bicycle class has three public member variables
  this.cadence = null;
  this.gear = null;
  this.speed = null;

  //constructor function
  this.__init = function(start_cadence, start_speed, start_gear){
    this.gear = start_gear;
    this.speed = start_speed;
    this.cadence = start_cadence;
  };

  this.set_cadence = function(value){
    this.cadence = value;
  };

  this.set_gear = function(value){
    this.gear = value;
  };

  this.apply_brake = function(decrement){
    this.speed -= decrement;
  };
 
  this.speed_up = function(increment){
    this.speed += increment;
  };

  this.get_speed = function(){
    return this.speed; 
  };
}, {super:true});

//definition of mountain_bike class, inheriting from the bicycle class
var mountain_bike = bicycle.extend(function(_super){
  this.__id__ = 'bicycle.mountain_bike';//this is optional for debugging purposes and can be any random string

  //the mountain_bike class adds one more public member variable
  this.seat_height = null;

  //constructor function
  this.__init = function(start_height, start_cadence, start_speed, start_gear){
    this.super(start_cadence, start_speed, start_gear);//call super prototype; EQUIVALENT TO: _super.__init.call(this, start_cadence, start_speed, start_gear);//call super prototype
    this.seat_height = start_height;
  };

  this.set_height = function(value){
    this.seat_height = value;
  };

	//we're shadowing the function speed_up of bicycle
	this.speed_up = function(increment){
		//on a mountainbike we're speeding up much faster
		this.speed += increment*1.2;
	};

  //we're shadowing the function get_speed of bicycle
  this.get_speed = function(){
    //but we're calling the function of the parent 
    return this.super();//EQUIVALENT TO: return _super.get_speed.call(this);
  };
}, {super:true});

var bicycle_instance = new bicycle(1, 10, 1);
var mountain_bike_instance = new mountain_bike(90, 1, 10, 1);

console.log(bicycle_instance.speed);//prints 10 as speed of has not been modified
bicycle_instance.speed_up(15);//speeding up by 15 (e.g. m/h)
console.log(bicycle_instance.speed);//prints 25 as speed of has not been modified
console.log(typeof bicycle_instance);//returns object
console.log(bicycle_instance instanceof earth.core.object);//prints true
console.log(bicycle_instance instanceof bicycle);//prints true
console.log(bicycle_instance instanceof mountain_bike);//prints false
try{
	bicycle_instance.set_height(5);
}catch(e){
  console.log('Bicycle does not have a set_height function');
}


console.log(mountain_bike_instance.speed);//prints 10 as speed of has not been modified
mountain_bike_instance.speed_up(5);//speeding up by 5 (e.g. m/h)
console.log(mountain_bike_instance.speed);//prints 16 (10+5*1.2);
console.log(mountain_bike_instance.get_speed() == mountain_bike_instance.speed);//returns true as shadowed function get_speed calls parent function get_speed, returning the current speed
console.log(typeof bicycle_instance);//returns object
console.log(mountain_bike_instance instanceof earth.core.object);//prints true
console.log(mountain_bike_instance instanceof bicycle);//prints true
console.log(mountain_bike_instance instanceof mountain_bike);//prints true 

PERFORMANCE COMPARISON

Performance comparison against the following libraries/scripts:

To run the performance tests, run

node performance/run_proprietary.js

There are two parameters available:

  • --benchmark/-b: the type of benchmark to run. Valid values: instantiation, public, static
  • --class/-c: the class that should be benchmarked.

Overall performance results

#Libraryops/mstotal time (in ms)total sample size
134rth13,3554,15140,000,000
2augment12,6634,37240,000,000
3native10,9054,41740,000,000
4Lava.ClassManager monomorphic9,4384,56440,000,000
5Typescript9,3774,65740,000,000
6jsface10,1404,96540,000,000
7Lava.ClassManager polymorphic8,9585,34840,000,000
8inherits8,6005,73840,000,000
9Fiber7,5816,02840,000,000
10John Resig’s Class3,77913,19440,000,000

Specific performance per example

Instantiation (inheritance depth 1)

#Libraryops/mstotal time (in ms)Sample Size
1augment20,734482.3110,000,000
234rth20,343491.5810,000,000
3native16,965589.4510,000,000
4jsface16,937590.4210,000,000
5inherits13,381747.3410,000,000
6Typescript13,336749.8710,000,000
7Lava.ClassManager polymorphic12,748784.4210,000,000
8Lava.ClassManager monomorphic12,093826.9310,000,000
9Fiber11,161895.9810,000,000
10John Resig's Class6,7441,482.7810,000,000

Instantiation (inheritance depth 2)

#Libraryops/mstotal time (in ms)Sample Size
134rth20,392490.3910,000,000
2augment17,876559.4210,000,000
3native13,636733.3710,000,000
4Lava.ClassManager polymorphic12,426804.7710,000,000
5jsface12,332810.8710,000,000
6Lava.ClassManager monomorphic11,824845.7410,000,000
7inherits11,194893.3110,000,000
8Typescript10,630940.7210,000,000
9Fiber9,2101,085.7810,000,000
10John Resig's Class3,8892,571.4910,000,000

Public Method Invocation (inheritance depth 1)

#Libraryops/mstotal time (in ms)Sample Size
1Typescript7,2151,385.9110,000,000
2native7,0491,418.7410,000,000
3Lava.ClassManager monomorphic6,9591,436.9810,000,000
434rth6,7861,473.6310,000,000
5augment6,3161,583.3510,000,000
6jsface6,0881,642.5610,000,000
7Lava.ClassManager polymorphic5,5301,808.4310,000,000
8Fiber5,3811,858.5210,000,000
9inherits5,3071,884.2710,000,000
10John Resig's Class2,5813,875.0110,000,000

Public Method Invocation (inheritance depth 2)

#Libraryops/mstotal time (in ms)Sample Size
1Lava.ClassManager monomorphic6,8761,454.4010,000,000
2Typescript6,3251,580.9310,000,000
3native5,9681,675.6210,000,000
434rth5,8991,695.1310,000,000
5augment5,7251,746.5910,000,000
6jsface5,2041,921.5810,000,000
7Lava.ClassManager polymorphic5,1261,950.8710,000,000
8Fiber4,5702,188.1110,000,000
9inherits4,5192,213.0810,000,000
10John Resig's Class1,9005,264.3210,000,000

Static Method Invocation

#Libraryops/mstotal time (in ms)Sample Size
134rth14,559686.8810,000,000
2Typescript13,608734.8410,000,000
3jsface12,938772.9210,000,000
4inherits12,279814.3810,000,000
5nativen\an\an\a
6John Resig's Classn\an\an\a
7Fibern\an\an\a
8Lava.ClassManager polymorphicn\an\an\a
9Lava.ClassManager monomorphicn\an\an\a
10augmentn\an\an\a

TESTS

For mocha test results see Travis CI.

node make.js && ./node_modules/mocha/bin/mocha
1.4.18

7 years ago

1.4.17

7 years ago

1.4.16

7 years ago

1.4.15

7 years ago

1.4.13

7 years ago

1.4.12

7 years ago

1.4.11

7 years ago

1.4.10

7 years ago

1.4.9

7 years ago

1.4.8

7 years ago

1.4.7

7 years ago

1.4.6

7 years ago

1.4.5

7 years ago

1.4.4

7 years ago

1.4.2

7 years ago

1.4.1

7 years ago

1.4.0

7 years ago

1.3.16

7 years ago

1.3.15

7 years ago

1.3.14

7 years ago

1.3.13

7 years ago

1.3.12

7 years ago

1.3.9

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

7 years ago

1.0.5

7 years ago