Home / iPhone Tips and Tutorials

Defining the constructor

Now we need to define our constructor after the use strict directive. This constructor will take a single parameter named options. We will then extend the defaults with the parameter options and store these settings that can be retrieved later, if needed. We will then ultimately cache the 'element' option as a Zepto object.

function App(options) {
    this.options = $.extend({}, _defaults, options);
    this.$element = $(this.options.element);
}

Here is what the previous code is accomplishing. First, we are using the keyword this, which is a reference to what will be, an instance of App itself. Thus, this is the context of the object itself. Hopefully, this is not too confusing and will become clear as we go on. In this case, we are using this to define an object options, which will contain the merged contents of _defaults and any custom options we pass into the constructor.

Note, when we pass an empty object, or {} into $.extend() as the first parameter, we are telling Zepto to merge _defaults and options into a new object, thus not overwriting the _defaults object. This is useful when we need to do some sort of check in the future with the default options.

Once we've defined the options, we then cache the element with this.$element, where $ in front of element is just for my reference so that immediately recognize a Zepto object versus a plain JavaScript object.

The prototype

We've created our App namespace, constructed an IIFE to contain our code and defined our constructor. Now, let's start creating some public methods that can be accessed to make this a bit modular. But before we do that, let's try to understand JavaScript's prototype.

Think of prototype as a live object that can be accessed, modified, and updated whenever and however you like. It can also be thought of as a pointer, because JavaScript will continue to go down the chain until it finds the object or it will return undefined. The prototype is simply a way of extending functionality to any non-plain object.

To make things a bit more confusing, I mentioned that non-plain objects have prototypes. These non-plain objects would be Arrays, Strings, Numbers, and so on. A plain object is one where we simple declare an empty object as follows:

var x = {};

The x variable does not have a prototype, it is simply there as a key/value storage similar to our _defaults object.

If you haven't yet understood the prototype, don't worry, it's all about getting your hands dirty and getting some experience. So, let's keep moving and getting our applications to work.

At this point, your App.js file should look like the following:

var App = window.App || {};
App = (function(window, document, $){
    'use strict';
    var _defaults = {
	'element': document.body,
	'name': 'App',
	// Configurable Options for each other class
	'videoOptions': {},
	'audioOptions': {},
	'touchOptions': {},
	'formOptions': {},
	'locationOptions': {},
	'singlePageOptions': {}
    };
    function App(options) {
	this.options = $.extend({}, _defaults, options);
	this.$element = $(this.options.element);
    }
}(window, document, Zepto));

Defining public methods

Now we need to create some public methods by typing into the prototype. We'll create a getDefaults method, which returns our default options; toString will overwrite the native toString method so we can return a custom name. Then we'll create initialization methods to create our other applications, and we'll name these initVideo, initAudio, initLocalization, initTouch, initForms, and initSinglePage respectively.

App.prototype.getDefaults = function() {
    return _defaults;
};

App.prototype.toString = function() {
    return '[ ' + (this.options.name || 'App') + ' ]';
};

App.prototype.initVideo = function() {
    App.Video.init(this.options.videoOptions);
    return this;
};

App.prototype.initAudio = function() {
    App.Audio.init(this.options.audioOptions);
    return this;
};

App.prototype.initLocalization = function() {
    App.Location.init(this.options.locationOptions);
    return this;
};

App.prototype.initTouch = function() {
    App.Touch.init(this.options.touchOptions);
    return this;
};

App.prototype.initForms = function() {
    App.Forms.init(this.options.formOptions);
    return this;
};

App.prototype.initSinglePage = function() {
    App.SinglePage.init(this.options.singlePageOptions);
    return this;
};

At this point we have several methods we can access publicly when we create an instance of App. First, let's review the code we implemented previously, specifically this line that gets duplicated, but customized based on the init method:

App.Touch.init(this.options.touchOptions);

For every init method we have created a call to the appropriate application, for example, App.Touch, App.Forms, App.Video, and so on. Then we pass it the options we've defined in the constructor that merged our defaults, for example, this.options.touchOptions, this.options.formOptions, this.options. videoOptions, and so on.

Note, we haven't created these classes yet for Video, Forms, Touch, and others, but we will be creating these soon.

Returning our constructor/function

The last thing we need to do in App.js includes returning the constructor. So, after all the public methods defined previously, include the following code:

return App;

This bit of code, although simple, is extremely important. Let's look at a stripped down version of App.js to better understand what's going on:

App = (function(){
    function App() {}
    return App;
}());

As mentioned earlier, we are creating an App namespace that gets set to the immediately invoked function expression. When we do this, we create a new scope inside this function.

This is why we can have a function or constructor with the name App as well and have no conflicts or errors. But if you recall, our function App is also an object, just like everything in JavaScript is an object. This is why, when we return our function App the App namespace gets set to the constructor. This then allows you to create multiple instances of App, while centralizing your code inside of a new scope that is untouchable.

[Previous] [Contents] [Next]