Photo of source code from this site

Objects and Singletons

Posted on:
March 19, 2015
Posted in:
JavaScript, Web Dev

I mentioned some time ago that I’d try to write up some of the rationale behind the coding decisions I made while building this site (since it’s as good a place to start as any). Today I figured it’d be good to talk about the difference between an Object and a Singleton.

Objects are reusable. You can create as many copies of that object as you want.

Singletons are defined and instantiated all at once. You can’t make multiple copies.

Other than that, they share a lot of functionality. Each can have member functions, data, and its own scope.

So let’s take a look at the YouTube code that I have running on this site. Since the YouTube IFRAMEs can’t respond to the page resizing like it does in a responsive environment, we need to create some JavaScript that’ll do the work for them.

First, we have an object that represents one IFRAME:

function mpYouTubeVideo (inObj) {
	this.obj = inObj;

	/**
	function resizeHandler
		arguments			e 			jQuery event
		returns				nothing
		description			Adjusts video size as responsive site moves around
	**/
	this.resizeHandler = function (e) {
		// get the parent width
		var parentWidth = $(this.obj.parentNode).innerWidth();

		// calculate video height assuming 16x9
		var vidHeight = parentWidth*9/16;

		// set video's width & height
		$(this.obj).css("width", parentWidth+"px");
		$(this.obj).css("height", vidHeight+"px");
	}

	// register resizeHandler & call
	$(window).resize(this.resizeHandler.bind(this));
	this.resizeHandler(null);
}

Next, we have a singleton that creates and manages several of these objects:

window.mpYouTubeManager = new function () {
	var videoList = null;

	/**
	function init
		arguments			none
		returns				nothing
		description			Scans page for videos and makes new objects to control them
	**/
	this.init = function () {
		this.videoList = new Array();

		$(".article-content iframe").each((function (idx, el){
			if (el.src.match(/youtube\.com/i)!==null) {
				this.videoList.push(new mpYouTubeVideo(el));
			}
		}).bind(this));
	};

	return this;
};

So here’s the difference: at this point in the code, window.mpYouTubeManager is a thing that exists. I can use its data and call its member functions. mpYouTubeVideo is a variable type. I can create many objects of that type using new mpYouTubeVideo(node).

Last, my startup routine:

$(document.body).ready(function () {
	mpGlobal.log("startup");
	window.mpLayoutHandler.init();
	window.mpMobileMenuManager.init();
	window.mpYouTubeManager.init();
});

When the page is ready, window.mpYouTubeManager.init() gets called. That function scans the page for IFRAME nodes. For any IFRAME nodes it finds that reference youtube.com, the singleton creates a new mpYouTubeVideo attached to that IFRAME node.

There are a few advantages:

  • The videos are all independent. They can take care of their own resizing.
  • There’s only one item added to the global scope, window.mpYouTubeManager.
  • The manager has access to all of the videos on the page and can perform later actions on them if needed. (It can even be queried by other singletons or functions.)
  • The startup sequence remains remarkably readable.

Most importantly, I never have to worry about namespace problems. Since there’s very little defined at the global level, I can use really simple names (like resizeHandler or videoList) over and over without fear of screwing something else up.