@roadmunk/jsclass

1.1.5 • Public • Published

Classes

JS.class creates a typical Javascript constructor Function that can be used to create new instances of Objects.

A class definition consists of two parts: the class name and the class properties.

Basic usage:

	const FirstClass = JS.class('FirstClass', {});
	let i = new FirstClass();

The name of the class can be any string. However, if it contains the period character, then the substring after the last period character will be used as the name of the returned Function that is displayed in the Chrome inspector.

The class properties is an Object whose keys define various attributes of the class like fields and methods (see below)

Fields

A class field stores a value for each instance that is created.

	const Point = JS.class('Point', {
		fields : {
			x : { type : Number },
			y : { type : Number }
		}
	});

	let d1 = new Point();
	d1.x = 5;
	d1.y = 10;

A field definition consists of an Object with a number of properties. These properties can be any key/value pair and can be read as meta-data for the field. Certain properties are used by the JS.class system namely:

type

Defines the Javascript constructor Function whose instance is expected to be assigned to this field. (eg: String, Object, Date, etc..) Unless there's an explicit init property, upon construction of a new instance of this class, the field will receive a new instance of this Function.

init

The initial value of the field after creating a new instance of this class. While this is traditionally done in the constructor, this field property allows the initial value assignment to be done with each field which puts it closer to the field definition. In any cases this eliminates the need for an explicit constructor function.

Primitive Value

When this is a primitive value (ie. number, string) then that is initial value for this field.

Function

When this is a Function, it is invoked and the result is the initial value for this field.

short-hand notation

There a couple of short-hand forms for the type and init fields. The type can be a primitive value (ie. 'hello world', 4) in which case this is shorthand notation for the init value and the type is derived from the type of initial value.

Eg:

{
	type : 'hello world'
}

is the same as

{
	type : String,
	init : 'hello world'
}

This is also the default property when a primitive value is supplied as the entire value of the field definition:

field : 43

is the same as:

field : {
	type : Number,
	init : 43
}

Constructor

This property is an optional function that is called during the creation of a new instance of this class. It is called after all the fields have been initialized to their default values. It's parameters are any values that were supplied during the construction call.

const Point = JS.class('Point', {
	constructor : function(x, y) {
		console.log(x, y);
	}
});

var a = new Point(4, -10);    // prints out 4, -10 to the console

Constructors in base classes are called automatically with the same arguments. There is currently no way to call base-class constructors explicitly.

Methods

This property defines methods that can be invoked on instances of the class.

const Point = JS.class('Point', {
	fields : {
		x : 0,
		y : 0
	},

	methods : {
		moveTo : function(newX, newY) {
			this.x = newX;
			this.y = newY;
		}
	}
});

var a = new Point();
a.moveTo(4, -10);

The context (ie. this) in an invoked method is the instance of the class.

Inheritence

This optional property defines another class which is the parent class of this one. The parent class's fields will be inherited and the parent class will be linked into the prototype chain for this class making any of it's methods available to this class.

const Circle = JS.class('Circle', {
	inherits : Point,

	fields : {
		radius : 1
	}
});

var a    = new Circle();
a.radius = 5;
a.moveTo(10, 10);

Calling super class methods

Within a method, the same method in the base class can be invoked by using this notation: this.method.super()

const Sphere = JS.class('Sphere', {
	inherits : Circle,

	fields : {
		z : 0
	},

	methods : {
		moveTo : function(x, y, z) {
			this.moveTo.super(x, y);
			this.z = z;
		}
	}
});

Mixins

A class can be mixed into another class. This means that all fields and methods of the mixin class are copied into the mixed-in class.

This allows a certain amount of re-use without resorting to inheritence since a class can only inherit from one other class.

A class can have more than one mixin in which case all fields and methods of the mixed in classes will be used in order of the declared mixins with later fields & methods replacing any previous ones.

const MyMixin = JS.class('MyMxin', {
	methods : {
		save : function() {}
	}
});

const Sphere = JS.class('Circle', {
	inherits : Point,
	mixin : [ MyMixin ]
});

var s = new Sphere();
s.save();

Abstract Classes

A class can be defined as having abstract fields and methods, which can be used to define an interface for all subclasses to implement.

const PersistableClass = JS.class('PersistableClass', {
	fields : {
		isSaved : { abstract : true },
	},

	methods : {
		save : { abstract : true },
	},
});

const MyModel = JS.class('MyModel', {
	fields : {
		isSaved : {
			get : function() { /* ... */ }
		}
	},

	methods : {
		save : function() { /* ... */ }
	}
});

Note that a class with any abstract properties cannot be instantiated, an error will be thrown if this is attempted.

Note: Before version 1.0.8, JSClass would only prevent instantiation of classes with abstract methods, but allowed instantiation of classes with abstract fields.

Static

A class can have static properties which are defined on the class object itself rather than on each instance.

const Point = JS.class('Point', {
	constructor : function() {
		Point.allPoints.push(this);
	},

	static : {
		fields : {
			allPoints : Array
		},

		methods : {
			getAllPoints : function() {
				return this.allPoints;
			}
		}
	}
});

new Point();
new Point();
console.log(Point.getAllPoints().length); // prints out 2

Note that in addition to a class inheritence hierarchy, there's also another hierarchy with the class objects themselves. Thus static properties are inherited by subclass class objects.

const Circle = JS.class('Circle', {
	inherits : Point
});

new Circle();
console.log(Circle.getAllPoints().length) // prints out 3

afterCreateClass()

If a static method is declared with this name, it will be called everytime there is a class defined that is a subclass of this class.

const BaseClass = JS.class('BaseClass', {
	static : {
		methods : {
			afterCreateClass : function(subclass) {
				// gets called with subclass === Subclass
			}
		}
	}
});

const Subclass = JS.class('Subclass', {
	inherits : BaseClass
});

This can be useful for creating a collection of all descendant subclasses in a base class.

Class Stubs

A class can be declared without it's definition being supplied. This allows the class to be used recursively during the definition of the class.

const Node = JS.class('Node');

JS.class(Node, {
	fields : {
		parentNode : {
			type : Node,
			init : null
		},

		firstChild : {
			type : Node,
			init : null
		},

		nextSibling : {
			type : Node,
			init : null
		}
	}
});

Class Events

fieldDefinition

Advanced

JS.getter

JS.setter

JS.class.initialFieldValue

JS.class.isSubclass

JS.class.isUnderConstruction

BaseClass.isSubclass

BaseClass.forEachField

BaseClass.hasMixin

BaseClass.getFieldProperties

BaseClass.isAbstract

Utils

JS.util.callback

JS.util.ensureArray

JS.util.proxy

JS.util.clone

Development

to run tests:

  1. npm install -g mocha
  2. mocha

Readme

Keywords

none

Package Sidebar

Install

npm i @roadmunk/jsclass

Weekly Downloads

1

Version

1.1.5

License

MIT

Unpacked Size

99 kB

Total Files

11

Last publish

Collaborators

  • bewmar
  • jbydeley
  • roadmunkit
  • cprhodes