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

@koga73/oop

v2.2.4

Published

This project when combined with design patterns adds common OOP functionality to JavaScript

Downloads

14

Readme

Build Status Support: IE8+ Dependencies: None License: MIT

OOP JS

This project when combined with design patterns adds common OOP functionality to JavaScript

Goals:

  • Provide OOP like functionality including namespacing, classes, inheritance, public / private scope
  • Provide a cross-browser event model that can be added to any object
  • Provide methods for cloning and extending objects
  • Provide methods for type checking

Install:

npm i @koga73/oop

Run unit tests:

Run NodeJS unit test:
npm test
Run HTML/JS unit test:
tests/test.html

examples/pong snippet:

(function(){
	//Imports from Pong example
	var Models = Pong.Models;
	var DomRenderer = Pong.Renderers.DomRenderer;
	var InputManager = Pong.Managers.InputManager;
	var NormalTimer = Utils.NormalTimer;
	
	//This returns a reference to the class. We are using the word "_class" as a shortcut to easily access static members
	var _class =
	namespace("Foo.Bar.Pong",
	construct({
	
		//Constants
		static:{
			ID_BALL:"ball",
			SPEED_BALL:400, //Pixels-per-second
			
			singleton:null,
			getSingleton:function(){
				if (!_class.singleton){
					_class.singleton = new Foo.Bar.Pong(
						_class.ID_BALL
					);
				}
				return _class.singleton;
			}
		},

		//In general _public is optional since it's the same as "this" (except in the scope of a private method)
		//Properties and methods starting with an underscore '_' are private
		instance:function(_private, _public){
			return {
				ball:null,

				normalTimer:null,
				inputManager:null,

				_renderer:null,
				_renderQueue:[],

				__construct:function(ballId){
					//Init game objects
					this.ball = new Models.Object2D(ballId);

					//Init game timer
					this.normalTimer = new NormalTimer({
						paused:false,
						onTick:_private._onTick
					});
					this.inputManager = InputManager.getSingleton();

					//Init renderer
					_private._renderer = new DomRenderer();
					_private._renderQueue = [
						this.ball
					];

					//--- LISTEN FOR EVENTS ---

					//Start
					this.resetBall();
				},

				//Delta is the time elapsed between ticks
				//Multiplying a movement value by delta makes the movement timebased rather than based on the clock cycle
				_onTick:function(delta){
					//Move
					var queueLen = _private._renderQueue.length;
					for (var i = 0; i < queueLen; i++){
						var obj2d = _private._renderQueue[i];
						obj2d.x += obj2d.moveX * delta;
						obj2d.y += obj2d.moveY * delta;
					}
					
					//--- DO LOGIC ---
					//Do something with _class.SPEED_BALL

					//Render
					_private._renderer.render(_private._renderQueue);
				},

				resetBall:function(){
					//--- DO LOGIC ---
				}
			};
		}
		
	}));
})();

Simple class:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:{
		width:100,
		height:200
	}
}));

var defaultShape = new foo.bar.Shape();
console.log(defaultShape);

Change scope:

This allows you to change the scope of OOP methods so don't have to put "OOP" all over the place.

//Add OOP methods to window/global by default or to any object passed in
OOP.changeScope();

namespace("foo.bar.Shape", construct({
	instance:{
		width:100,
		height:200
	}
}));

var defaultShape = new foo.bar.Shape();
console.log(defaultShape);

Constructor:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:{
		width:100,
		height:200,

		__construct:function(newWidth, newHeight){
			this.width = newWidth || this.width;
			this.height = newHeight || this.height;
			console.log("This gets called when a new instance is created", this.width, this.height);
		}
	}
}));

//Note that if we pass in non-object parameters they will get sent to the constructor
//Object type parameters will apply value overrides to the instance
var customShape = new foo.bar.Shape(300, 400, {
	test:"this prop gets added to the instance"
});
console.log(customShape);

Static:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:{
		width:100,
		height:200,
	},

	static:{
		SOME_CONST:123,

		getArea:function(obj){
			return obj.width * obj.height;
		}
	}
}));

var instance = new foo.bar.Shape({
	width:300,
	height:400
});
console.log(foo.bar.Shape.SOME_CONST);
console.log(foo.bar.Shape.getArea(instance));

Public / Private scope:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:function(_private, _public){
		return {
			width:100,
			height:200
			_thisIsPrivate:"some message",

			getThisIsPrivate:function(){
				return _private._thisIsPrivate;
			}
		};
	}
}));

var defaultShape = new foo.bar.Shape();
console.log(defaultShape);

Note that when a function is passed to "instance" a public and private scope is created. Anything starting with an underscore '_' is private. You can use the _private and _public references passed into the function to call between scopes. Optionally "this" refers to the _public or _private scope respectively. You can also use these _public and _private variables to avoid creating event delegates for "this".


Inheritance:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:{
		width:100,
		height:200
	},

	static:{
		getArea:function(obj){
			return obj.width * obj.height;
		}
	}
}));

OOP.namespace("foo.bar.Triangle", OOP.inherit(foo.bar.Shape, OOP.construct({
	instance:{
		width:300,
		angles:[30, 60, 90]
	},

	static:{
		getArea:function(obj){
			return obj.width * obj.height * 0.5;
		}
	}
})));

var triangle = new foo.bar.Triangle();
console.log(OOP.isType(triangle, foo.bar.Triangle)); //true
console.log(OOP.isType(triangle, "foo.bar.Triangle")); //true
console.log(OOP.isType(triangle, foo.bar.Shape)); //true
console.log(triangle._interface); //Triangle instance
console.log(triangle._super); //Shape instance
console.log(triangle._super._interface); //Triangle instance
console.log(triangle._type); //"foo.bar.Triangle"
console.log(triangle._super._type); //"foo.bar.Shape"

Events:

OOP.namespace("foo.bar.Shape", OOP.construct({
	instance:{
		width:100,
		height:200
	},
	events:true,

	static:{
		getArea:function(obj){
			return obj.width * obj.height;
		}
	}
}));

var instance = new foo.bar.Shape();
instance.addEventListener("test-event", function(evt, data){
	console.log("Got event", evt, data);
});

instance.dispatchEvent(new OOP.Event("test-event", 123));

Note that events fired from inherited classes (_super) will bubble up (they share the same _eventHandlers)

Add events to any object:

var myObj = {};
OOP.addEvents(myObj);

myObj.addEventListener("test-event", function(evt, data){
	console.log("Got event", evt, data);
});

myObj.dispatchEvent(new OOP.Event("test-event", 123));

Clone:

var obj = OOP.clone({foo:{bar:"foobar"}}); //Makes a deep copy - The foo objects will be different
var obj = OOP.clone({foo:{bar:"foobar"}}, false); //Makes a shallow copy - The foo objects will be the same reference

Extend:

var foo = {abc:123};
var bar = {def:{ghi:456}};

//Extend bar onto foo - deep by default meaning foo.def will not equal bar.def
OOP.extend(foo, bar);

//Extend bar onto foo - shallow meaning foo.def and bar.def will be the same reference
OOP.extend(foo, false, bar);

//Extend bar onto foo - shallow meaning foo.def and bar.def will be the same reference but the third object is deep again
OOP.extend(foo, false, bar, true, {jkl:{mno:789}});

Note the number of arguments is unlimited. When a boolean is encountered it sets the "deep" flag for subsequent objects. The first object found in the arguments is what gets extended (you could pass true/false as the first argument).

Type checks:

OOP.isType
OOP.isFunction
OOP.isArray
OOP.isObject
OOP.isString
OOP.isBoolean
OOP.isRegExp

Full API:

init:_methods.init,

//Class
namespace:_methods.namespace,
inherit:_methods.inherit,
createClass:_methods.createClass,
construct:_methods.construct,

//Core
clone:_methods.clone,
extend:_methods.extend,

//Type checks
isType:_methods.isType,
isFunction:_methods.isFunction,
isArray:_methods.isArray,
isObject:_methods.isObject,
isString:_methods.isString,
isBoolean:_methods.isBoolean,
isRegExp:_methods.isRegExp,

//Events
Event:_methods.event,

addEvents:_methods.addEvents,
removeEvents:_methods.removeEvents,

addEventListener:_methods.addEventListener,
on:_methods.addEventListener, //Alias

removeEventListener:_methods.removeEventListener,
off:_methods.removeEventListener, //Alias

dispatchEvent:_methods.dispatchEvent,
trigger:_methods.dispatchEvent, //Alias
emit:_methods.dispatchEvent //Alias