npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

class-advanced

v2.1.3

Published

Universal JS classes helper - extending, constructors, static and dynamic elements, parent methods calls, self reflection, late static binding. For all browsers, Node.js, Windows Script Host and Adobe Javascript.

Downloads

8

Readme

Javascript Class (Class.js)

Latest Stable Version License

Universal JS library for prototyped classes - extending, constructor, static and dynamic elements, parent methods calls, self reflection and much more. For all browsers, Node.js and Windows Script Host.

INSTALATION

npm install oop-class

DOWNLOAD

<!-- for production: -->
<script type="text/javascript" src="https://tomflidr.github.io/class.js/builds/2.1.3/class.min.js"></script>

<!-- for development with JSDocs comments for IDE: -->
<script type="text/javascript" src="https://tomflidr.github.io/class.js/builds/2.1.3/class.dev.js"></script>

DEMOS

Features

  • very fast, effective, supersmall - all in 6.5 KB - minimized, 2.4 KB - gzipped
  • multi environment:
    • all browsers (MSIE6+, Safari, Opera, Chrome)
    • Node.js
    • WSH (Windows Script Host)
    • Adobe (only old archived version 0.6)
  • syntax customization - any declaration keyword or internal class keyword shoud be customized
  • inspired by PHP OOP, Ext.JS and Prototype.JS syntax
  • documented with JSDocs comments
  • Function.prototype.bind polyfill included
  • possibility to define:
    • Static elements
    • parent class by Extend keyword
    • Constructor method
    • all other elements as dynamic elements
  • possibility to call any dynamic and static parent method anywhere by:
    • this.parent(arguments); // in static and dynamic functions
    • this.parent(param1, param2); // in static and dynamic functions
    • this.parent.anyStaticMethod(param1, param2); // in static functions
    • this.parent.anyDynamicMethod(param1, param2); // in dynamic functions
    • this.parent.apply(this, [param1, param2]); // in static and dynamic functions
    • this.parent.anyStaticMethod.apply(this, [param1, param2]); // in static functions
    • this.parent.anyDynamicMethod.apply(this, [param1, param2]); // in dynamic functions
  • posibility to get current class definition by:
    • this.self; // without the need to know class name itself
    • this.static; // without the need to know class name itself
    • this.self context (static class definition) is changed in each defined dynamic and static method into value coresponded with original definition place
    • this.static context (static class definition) is not changed and it all time coresponds to original instance context - like Late Static Bindings in PHP OOP
  • posibility to get class name / fullname / namespace (only if class is defined by Class.Define();) by:
    • this.self.Fullname; or this.static.Fullname;
    • this.self.Name; or this.static.Name;
    • this.self.Namespace; or this.static.Namespace;
  • posibility to create instance by:
    • classic Javascript new keyword: var instance = new ClassName(param1, param2);
    • class name string with Class.Create(); method: var instance = Class.Create('ClassName', param1, param2);
  • inheritance checking by javascript 'instanceof' keyword
  • posibility to create anonymous classes like:
    • new Class({Constructor:function(text){console.log(text)}})("It works!");
  • Visual Studio - Go To Definition (F12) support - for current level objects and parent methods

1. Basic Class - Animal

// Declare not named class by Class(...) 
// call into custom variable 'Animal':
var Animal = Class({
	Constructor: function (name, sound) {
		this.name = name;
		this.sound = sound;
	},
	name: '',
	sound: '',
	MakeNoise: function () {
		console.log(this.sound);
	},
	IntroduceYourself: function () {
		console.log(
			"People call me '{0}'.".format(this.name)
		);
	}
});

// Create instance:
var dog = new Animal('Charlie', 'Wrr haf!');

// 'Wrr haf!'
dog.MakeNoise();

// 'People call me 'Charlie'.'
dog.IntroduceYourself();

2. Class Dog And Cat Extends Animal

// Declare named class by Class.Define(...) 
// call into global memory space as 'Animal'
Class.Define('Animal', {
	Static: {
		GetInstance: function () {
			// this.static contains a child class definition
			// as later static binding in PHP normaly works
			return new this.static(arguments);
		}
	},
	Constructor: function (name, sound) {
		this.name = name;
		this.sound = sound;
	},
	name: '',
	sound: '',
	MakeNoise: function () {
		console.log(this.sound);
	},
	IntroduceYourself: function () {
		console.log(
			"People call me '{0}'.".format(this.name)
		);
	},
	DefineYourself: function (asdf) {
		console.log(
			"Globaly, I'm an '{0}'.".format(this.self.Name)
			+ '<br />' +
			"More precisely, I'm a '{0}'.".format(this.static.Name)
			+ '<br />' +
			"I live like an '{0}'.".format(this.static.Namespace)
			+ '<br />' +
			"My namespace is '{0}'.".format(this.static.Fullname)
		);
	},
	TellYourStory: function () {
		this.MakeNoise();
		this.DefineYourself();
	}
});

// Declare named classes by Class.Define(...) call 
// into global memory space as 'Animal.Dog' and 'Animal.Cat'
// as extended classes from 'Animal' class.
Class.Define('Animal.Dog', {
	Extend: Animal,
	TellYourStory: function () {
		this.MakeNoise();
		this.IntroduceYourself();
		this.DefineYourself();
		console.log("But I'm the best friend of human.")
	}
});
Class.Define('Animal.Cat', {
	Extend: Animal,
	TellYourStory: function () {
		this.MakeNoise();
		this.IntroduceYourself();
		this.DefineYourself();
		console.log(
			"I don't care about people, but sometimes <br />"+
			"they have something very good to eat."
		);
	}
});

// Create instances (all ways are creating an instance):
var creature = Class.Create("Animal", "Creature", "Rrroooaaarrr!")
var dog = new Animal.Dog("Charlie", "Wrr haf!");
var cat = Animal.Cat.GetInstance('Suzy', 'Pchchchchch!');



// 'Rrroooaaarrr!'

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Animal'.
// I belong to namespace ''.
// My full description is 'Animal'.
creature.TellYourStory();


console.log("-------------------");


// 'Wrr haf!'
// People call me 'Charlie'.

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Dog'.
// I live between 'Animal'.
// My type is 'Animal.Dog'.

// But the best friend of human.
dog.TellYourStory();


console.log("-------------------");


// Pchchchchch! [String]
// People call me 'Suzy'. [String]

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Cat'.
// I live between 'Animal'.
// My type is 'Animal.Cat'. [String]

// I don't care about people, but sometimes 
// they have something very good to eat.
cat.TellYourStory();


console.log("-------------------");

console.log(dog instanceof Animal); // true
console.log(dog instanceof Animal.Dog); // true
console.log(dog instanceof Animal.Cat); // false
console.log(dog instanceof Date); // false

console.log("-------------------");

console.log(dog.static.Name); // 'Dog'
console.log(dog.static.Fullname); // 'Animal.Dog'
console.log(dog.static.Namespace); // 'Animal'
console.log(dog.static.Extend.Name); // 'Animal'
console.log(dog.static.Extend.Fullname); // 'Animal'
console.log(dog.static.Extend.Namespace); // ''

console.log("-------------------");

console.log(dog.static === Animal.Dog); // true
console.log(dog.static.Extend === Animal); // true
console.log(dog.static.prototype === Animal.Dog.prototype); // true
console.log(dog.static.Extend.prototype === Animal.prototype); // true

console.log("-------------------");

console.log(typeof Animal.Dog); // 'function'
console.log(typeof dog); // 'object'
console.log(dog.toString()); // '[object Animal.Dog]'

4. Three Extended Classes With Static Members

Class.Define('Person', {
	Static: {
		Store: [],
		Count: 0,
		Register: function (person) {
			// in Static block:
			// - this context represents static context environment
			this.Store[person.id] = person;
			this.Count += 1;
		}
	},
	Constructor: function (id, name) {
		// in Constructor and dynamic methods:
		// - this context represents dynamic context environment
		this.id = id;
		this.name = name;
		this.self.Register(this);
	},
	id: 0,
	name: ''
});

Class.Define('Employe', {
	Extend: Person,
	Constructor: function (id, name, salary) {
		this.parent(id, name);
		this.salary = salary;
	},
	salary: 0,
	GetInfo: function () {
		return this.static.Name + " - name: " + this.name
			+ ", id: " + this.id + ", salary: " + this.salary;
	}
});

Class.Define('Manager', {
	Extend: Employe,
	Constructor: function (id, name, salary, idSecretary) {
		this.parent(id, name, salary);
		this.idSecretary = idSecretary;
	},
	idSecretary: 0,
	GetInfo: function () {
		var parentInfo = this.parent();
		return parentInfo + ",<br />"
			+ "&nbsp;&nbsp;&nbsp;" + "- secretary: "
			+ this.self.Store[this.idSecretary].GetInfo();
	}
});

// create class instance in standard way
var prManager = new Manager(0, 'Douglas Bridges', 50000, 1);

// create class instance by string as first argument, 
// all constructor params as second argument array
var secretary = Class.Create('Employe', 1, 'Janet Williams', 30000);

// 'Employe - name: Janet Williams, id: 1, salary: 30000'
console.log(secretary.GetInfo());

// 'Manager - name: Douglas Bridges, id: 0, salary: 50000,
// - secretary: Employe - name: Janet Williams, id: 1, salary: 30000'
console.log(prManager.GetInfo());

// Primitive values are not linked,
// so real count of registered persons
// is written in Person.Count memory space
console.log(Person.Count);	// 2
console.log(Employe.Count);	// 0
console.log(Manager.Count);	// 0

// Nonprimitive values are lined as references,
// so registered persons store is written 
// in Person.Count memory space and two another links are created
console.log(Person.Store.length);	// 2
console.log(Employe.Store.length);	// 2
console.log(Manager.Store.length);	// 2

5. Three Controller Classes And Different Behaviour In Actions

// System controller class - parent for all controllers:
Class.Define('Controller', {
	Static: {
		Dispatch: function (path, actionName) {
			new this.static(path)[actionName + 'Action']().Render();
		}
	},
	Constructor: function (path) {
		this.path = path;
	},
	path: null,
	Render: function () {
		console.log(JSON.stringify(this.path));
	}
});

// Front controller class - parent for all front controllers:
Class.Define('Controller.Front', {
	Extend: Controller,
	prepareView: function () {
		this.view = {
			path: this.path,
			agent: navigator.appName,
			lang: navigator.language
		};
	},
	view: null,
	Render: function () {
		console.log(
			JSON.stringify(this.view, null, "  ")
		);
	}
});

// Specific controller class for text pages,
// this controller will be dispatched 4 times:
Class.Define('Controller.Front.Default', {
	Extend: Controller.Front,
	prepareView: function () {
		this.parent(arguments);
		this.view.content = "You are here: '{0}'."
			.format(this.view.path.substr(1));
		this.view.layout = 'two-columns';
		this.view.leftMenu = [
			'About', 'Partners', 'Contacts'
		];
	},
	HomeAction: function () {
		/*****************************************************/
		/* You can call parent method directly from         **/
		/* any other method to skip current implementation! **/
		this.parent.prepareView();
		/*****************************************************/
		this.view.content = 'Welcome to our website!';
		this.view.layout = 'one-column';
		return this;
	},
	DefaultAction: function () {
		this.prepareView();
		return this;
	},
	ContactsAction: function () {
		this.prepareView();
		this.view.contactMain = '[email protected]';
		return this;
	}
});


// Dispatching different requests to different 
// actions with different needs:

var ctrlDef = Controller.Front.Default;

ctrlDef.Dispatch('/home',		'Home');
ctrlDef.Dispatch('/about-us',	'Default');
ctrlDef.Dispatch('/partners',	'Default');
ctrlDef.Dispatch('/contacts',	'Contacts');

6. Class A, B, C And Parent Methods Calls Flows

Class.Define('A', {
	Static: {
		Create: function (one, two, three) {
			console.log(this.self.Name + '::Create(' + one + ',' + two + ',' + three + ')');
			return Class.Create(this.static.Name, arguments);
		},
		FirstStatic: function (a, b, c) {
			console.log(this.self.Name + '::FirstStatic(' + a + ',' + b + ',' + c + ')');
		}
	},
	Constructor: function (one, two, three) {
		console.log(this.self.Name+'->Constructor('+one+','+two+','+three+')');
	},
	FirstDynamic: function (f, g, h) {
		console.log(this.self.Name+'->FirstDynamic('+f+','+g+','+h+')');
		return this;
	},
	SecondDynamic: function (x, y, z) {
		console.log(this.self.Name+'->SecondDynamic('+x+','+y+','+z+')');
		return this;
	},
	ThirdDynamic: function (x, y, z) {
		console.log(this.self.Name+'->ThirdDynamic('+x+','+y+','+z+')');
		return this;
	}
});

Class.Define('B', {
	Extend: A,
	Static: {
		FirstStatic: function (a, b, c) {
			console.log("this is never called");
		},
		SecondStatic: function (a, b, c) {
			console.log(this.self.Name+'::SecondStatic('+a+','+b+','+c+')');
			this.parent.FirstStatic(a, b, c);
		}
	},
	Constructor: function (one, two, three) {
		console.log(this.self.Name+'->Constructor('+one+','+two+','+three+')');
		this.parent(arguments);
	},
	FirstDynamic: function (x, y, z) {
		console.log(this.self.Name+'->FirstDynamic('+x+','+y+','+z+')');
		this.ThirdDynamic(x, y, z);
		return this;
	},
	ThirdDynamic: function (x, y, z) {
		console.log(this.self.Name+'->ThirdDynamic('+x+','+y+','+z+')');
		this.parent.ThirdDynamic(x, y, z);
		return this;
	}
});

Class.Define('C', {
	Extend: B,
	Static: {
		SecondStatic: function (a, b, c) {
			console.log("this is never called");
		},
		ThirtStatic: function (a, b, c) {
			console.log(this.self.Name + '::ThirtStatic(' + a + ',' + b + ',' + c + ')');
			this.parent.SecondStatic(a, b, c);
		}
	},
	one: 0,
	two: 0,
	three: 0,
	Constructor: function (one, two, three) {
		this.one = one;
		this.two = two;
		this.three = three;
		console.log(this.self.Name+'->Constructor('+one+','+two+','+three+')');
		this.parent(arguments);
	},
	FirstDynamic: function (f, g, h) {
		console.log(this.self.Name+'->FirstDynamic('+f+','+g+','+h+')');
		this.parent.SecondDynamic(f, g, h);
		return this;
	},
	SecondDynamic: function (m, n, o) {
		console.log(this.self.Name+'->SecondDynamic('+m+','+n+','+o+')');
		this.ThirdDynamic(m, n, o);
		return this;
	},
	ThirdDynamic: function (x, y, z) {
		console.log(this.self.Name+'->ThirdDynamic('+x+','+y+','+z+')');
		this.parent.FirstDynamic(x, y, z);
		return this;
	}
});


/**
This code flows through methods:
	C::ThirtStatic(a,b,c)
		B::SecondStatic(a,b,c)
			A::FirstStatic(a,b,c)
	C::Create(1,2,3)
*/
C.ThirtStatic('a', 'b', 'c');


/**
This code flows through methods:
	C->Constructor(1,2,3)
		B->Constructor(1,2,3)
			A->Constructor(1,2,3)
*/
var c = C.Create(1, 2, 3)
	/**
	This code flows through methods:
		C->FirstDynamic(f,g,h)
				A->SecondDynamic(f,g,h)
	*/
	.FirstDynamic('f', 'g', 'h')
	/**
	This code flows through methods:
		C->SecondDynamic(m,n,o)
		C->ThirdDynamic(m,n,o)
			B->FirstDynamic(m,n,o)
			B->ThirdDynamic(m,n,o)
				A->FirstDynamic(m,n,o)
	*/
	.SecondDynamic('m', 'n', 'o')
	/**
	This code flows through methods:
		C->ThirdDynamic(x,y,z)
			B->FirstDynamic(x,y,z)
				A->ThirdDynamic(x,y,z)
	*/
	.ThirdDynamic('x', 'y', 'z');

console.log(c.toString()); // [object C]

7. Syntax Customization

// syntax customization at app start:
Class.define = Class.Define;
Class.create = Class.Create;
Class.getByName = Class.GetByName;
Class.CustomizeSyntax({
	GetClassUid		: 'getClassUid',
	GetInstanceUid	: 'getInstanceUid',
    Inherited		: 'inherited',
	Extend			: 'extend',
	Static			: 'static',
	// for 'constructor' is not possible to use javascript 
	// build in function property 'constructor', use different:
	Constructor: 'construct',
	// for 'name' is not possible to use javascript 
	// build in 'Function.name' property, use different:
	Name			: 'className',
	Fullname		: 'classFullname',
	Namespace		: 'classNamespace',
	static			: 'static',
	self			: 'self',
	parent			: 'parent'
});


// Declare named class by Class.Define(...) 
// call into global memory space as 'Animal'
Class.define('Animal', {
	static: {
		getInstance: function () {
			// this.static contains a child class definition
			// as later static binding in PHP normaly works
			return new this.static(arguments);
		}
	},
	construct: function (name, sound) {
		this.name = name;
		this.sound = sound;
	},
	name: '',
	sound: '',
	makeNoise: function () {
		console.log(this.sound);
	},
	introduceYourself: function () {
		console.log(
			"People call me '{0}'.".format(this.name)
		);
	},
	defineYourself: function () {
		console.log(
			"Globaly, I'm an '{0}'.".format(this.self.className)
			+ '<br />' +
			"More precisely, I'm a '{0}'.".format(this.static.className)
			+ '<br />' +
			"I belong to namespace '{0}'.".format(this.static.classNamespace)
			+ '<br />' +
			"My full description is '{0}'.".format(this.static.classFullname)
		);
	},
	tellYourStory: function () {
		this.makeNoise();
		this.defineYourself();
	}
});

// Declare named classes by Class.Define(...) call 
// into global memory space as 'Animal.Dog' and 'Animal.Cat'
// as extended classes from 'Animal' class.
Class.define('Animal.Dog', {
	extend: Animal,
	tellYourStory: function () {
		this.makeNoise();
		this.introduceYourself();
		this.defineYourself();
		console.log("But I'm the best friend of human.")
	}
});
Class.define('Animal.Cat', {
	extend: Animal,
	tellYourStory: function () {
		this.makeNoise();
		this.introduceYourself();
		this.defineYourself();
		console.log(
			"I don't care about people, but sometimes <br />" +
			"they have something very good to eat."
		);
	}
});

// Create instances:
var creature = Class.create("Animal", "Creature", "Rrroooaaarrr!")
var dog = new Animal.Dog("Charlie", "Wrr haf!");
var cat = Animal.Cat.getInstance('Suzy', 'Pchchchchch!');



// 'Rrroooaaarrr!'

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Animal'.
// I belong to namespace ''.
// My full description is 'Animal'.
creature.tellYourStory();


console.log("-------------------");

// 'Wrr haf!'
// People call me 'Charlie'.

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Dog'.
// I live between 'Animal'.
// My type is 'Animal.Dog'.

// But the best friend of human.
dog.tellYourStory();


console.log("-------------------");


// Pchchchchch! [String]
// People call me 'Suzy'. [String]

// Globaly, I'm an 'Animal'.
// More precisely, I'm a 'Cat'.
// I live between 'Animal'.
// My type is 'Animal.Cat'. [String]

// I don't care about people, but sometimes 
// they have something very good to eat.
cat.tellYourStory();



console.log("-------------------");

console.log(dog instanceof Animal); // true
console.log(dog instanceof Animal.Dog); // true
console.log(dog instanceof Animal.Cat); // false
console.log(dog instanceof Date); // false

console.log("-------------------");

console.log(dog.static.className); // 'Dog'
console.log(dog.static.classFullname); // 'Animal.Dog'
console.log(dog.static.classNamespace); // 'Animal'
console.log(dog.static.extend.className); // 'Animal'
console.log(dog.static.extend.classFullname); // 'Animal'
console.log(dog.static.extend.classNamespace); // ''

console.log("-------------------");

console.log(dog.static === Animal.Dog); // true
console.log(dog.static.extend === Animal); // true
console.log(dog.static.prototype === Animal.Dog.prototype); // true
console.log(dog.static.extend.prototype === Animal.prototype); // true

console.log("-------------------");

console.log(typeof Animal.Dog); // 'function'
console.log(typeof dog); // 'object'
console.log(dog.toString()); // '[object Animal.Dog]'

Browser Usage

  • install any browser if necessary (MSIE6+, Firefox, Google Chrome, Safari, Opera...)
  • create new empty text file with name "example.html":
  • open the file "example.html" in the browser to run
<!DOCTYPE HTML>
<html lang="en-US">
	<head>
		<meta charset="UTF-8" />
	</head>
	<body>
		<script src="./class.dev.js" type="text/javascript"></script>
		<script type="text/javascript">
			var MyClass = Class({
				Constructor: function () {
					console.log("It works!");
				}
			});
			var myInstance = new MyClass(); // "It works!
		</script>	
	</body>
</html>

Node.js Usage

  • install node.js from nodejs.org if necessary
  • create new empty text file with name "example.js":
  • type into command line window "node example.js" to run
require('class-advanced');
var MyClass = Class({
	Constructor: function () {
		console.log("It works!");
	}
});
var myInstance = new MyClass(); // "It works!

Windows Script Host Usage

  • create new empty text file with name "example.wsf":
  • doubleclick on the file "example.wsf" to run
<job>
	<script type="JScript" src="./class.dev.js"></script>
	<script type="JScript">
		var MyClass = Class({
			Constructor: function () {
				WScript.echo("It works!");
			}
		});
		var myInstance = new MyClass(); // "It works!
	</script>
</job>

DEMOS