
This is my web development cheat-sheet to make things easier when creating new web pages, etc. It should be considered a living document but the publish date will be kept as specified in its first edition so it doesn’t regularly top the articles list.
In this article:
- Basic HTML Structure
- Use Bootstrap for CSS
- JavaScript Extension Methods
- Using JavaScript Closures
- Creating Reusable JavaScript Packages
- JavaScript Classes
Basic HTML Structure
To save having to manually type/format new web pages each time, just copy and paste this!
<!DOCTYPE html>
<html lang="en-GB">
<head>
<!-- <meta http-equiv="X-UA-Compatible" content="IE=10" /> <!-- Stops IE going into IE7 compatibility mode. -->
<!-- <meta http-equiv="expires" content="0"> <!-- Forces page reload each time refresh button clicked. -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- For mobile device scaling, etc. -->
<link rel="SHORTCUT ICON" href="images/siteicon.ico" /> <!-- site icon. -->
<title>Page Title</title>
</head>
<body>
<!-- Content in here!-->
</body>
</html>
Code language: HTML, XML (xml)
Use Bootstrap for CSS
This saves a load of time trying to produce your own. Bootstrap can also be easily tweaked as described in this article:
Modifying Bootstrap Styles – The Right Way.
Some JavaScript Extension Methods
A minimal set of extension functions to fill the gaps in JavaScript functionality…
(Recommend creating an extends.js file (or something similarly named) and dumping the extension methods in there.)
/* This inline code-fragment adds the string.trim() function if it doesn't exist (like in IE8, etc.) */
if (typeof String.prototype.trim !== 'function') {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
}
}
/* This inline code-fragment adds a string.pad() function to allow fixed-width formatting of strings. */
if (typeof String.prototype.pad !== 'function') {
/**
* Provides an extension method to pad out strings to a fixed minimum length.
* @param {string} paddingChar - the character to pad out the string using.
* @param {number} totalLength - the length to make the string.
* @param {boolean} padLeft - true to left-pad the string (so the existing content is right-most), or false to right-pad it.
* @returns {string} the padded string value.
*/
String.prototype.pad = function(paddingChar, totalLength, padLeft) {
if (typeof paddingChar === 'undefined' || totalLength &amp;lt;= this.length) {
return this;
}
var padding = Array(totalLength).join(paddingChar);
if (typeof padLeft === 'undefined' || padLeft) {
return (padding + this).slice(-totalLength);
} else {
return (this + padding).substring(0, totalLength);
}
}
}
/* This inline code-fragment adds the Date.format() function to allow formatting of date/time values as text. */
if (typeof Date.prototype.format !== 'function') {
/**
* Provides a formatted string value for the current date object.
* @param {string} format - the formatting specification to use (employs C#.NET styling (i.e. not jQuery style.))
* @returns {string} a string value representing the formatted date/time.
*/
Date.prototype.format = function(format) {
var day = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
var month = ['January','February','March','April','May','June','July','August','September','October','November','December'];
var dayOfMonth = this.getDate().toString();
var monthIndex = this.getMonth();
var year = this.getFullYear().toString();
var shortYear = this.getFullYear().toString().substring(0,2);
var hours = this.getHours().toString();
var amPmHours = (this.getHours() &amp;gt; 12 ? this.getHours() - 12 : this.getHours()).toString();
var minutes = this.getMinutes().toString();
var seconds = this.getSeconds().toString();
var amPm = this.getHours() &amp;gt; 12 ? 'PM' : 'AM';
return format.replace(/HH/g, hours.pad('0', 2, true)).replace(/H/g, hours)
.replace(/hh/g, amPmHours.pad('0', 2, true)).replace(/h/g, amPmHours)
.replace(/mm/g, minutes.pad('0', 2, true)).replace(/m/g, minutes)
.replace(/ss/g, seconds.pad('0', 2, true)).replace(/s/g, seconds)
.replace(/tt/g, amPm).replace(/t/g, amPm.substring(0, 1))
.replace(/dddd/g, day[this.getDay()]).replace(/ddd/g, day[this.getDay()].substring(0,3))
.replace(/dd/g, dayOfMonth.toString().pad('0', 2, true))
.replace(/yyyy/g, year).replace(/yy/g, shortYear)
.replace(/MMMM/g, month[monthIndex]).replace(/MMM/g, month[monthIndex].substring(0,3))
.replace(/MM/g, (monthIndex + 1).toString().pad('0', 2, true));
}
}
Code language: JavaScript (javascript)
Using JavaScript Closures
Closures are a good way of exposing only the functionality you want. They wrap functionality into an anonymous function so that only
its publicly visible parts are available to the outside world. This can be thought of (to some extent) as being similar to static classes in object orientated languages.
var pkg = (function () {
var privateVariable = 0;
function privateFunction() {
// do something with the privateVariable!
}
return function () {
// public function that will be executed.
}
})();
pkg(); // Executes the nested 'public function'.
Code language: JavaScript (javascript)
What is interesting is that closures have access to the parent scope AFTER their outer function has finished executing. For example, the following is a closure scenario too:
function ukIntel(surname) {
var suffix = ', 007 - licensed to kill';
return ({
function display(firstName) {
return surname + ", " + firstName + " " + surname + suffix;
}
});
}
var spy = ukIntel('Bond');
alert(spy.display('James'));
Code language: JavaScript (javascript)
Not that we don’t have to declare the function anonymously, and we don’t have to assign the outer variable when the outer function is defined (like we did in the previous example) either. Here, a function (ukIntel) is defined, and then associated with a variable separately. When the outer function is called, only the surname is assigned and the function returns. The interesting thing is that the ‘spy’ variable now references the inner function (display), but has access to the outer function properties still. In this way, calling the display function would cause an alert to be displayed, showing:
Bond, James Bond, 007 – licensed to kill
You can pass parameters into an anonymous function hosting closures using the function signature, like so:
var lastName = 'Lighter';
var spy = (function(surname) {
var suffix = ', CIA - or am I?!';
return ({
display: function(firstName) {
return surname + ", " + firstName + " " + surname + suffix;
}
});
})(lastName);
alert(spy.display('Felix'));
Code language: JavaScript (javascript)
Creating Reusable JS Packages
This uses closures again – in fact most JavaScript packages/frameworks/APIs seem to. The simple wrapping example just expands upon the description of closures above, demonstrating how data and functions can be kept private, and specific functionality can be publicly exposed.
Simple Wrapping
Simple wrapping of JavaScript functionality is as simple as declaring a global variable…
var myPkg = (function() {
var privateVariable = 0;
function privateFunction() {
// do something!
}
return ({
publicFunction1: function(arg1, arg2) {
//do something with arg1 and arg2 parameters!
},
publicFunction2: function() {
//do something else!
}
});
})();
Code language: JavaScript (javascript)
In the above scenario, myPkg becomes the means of accessing functionality within the anonymous function, such that only the public functions are visible. Calling the functions elsewhere in JS code is simple:
myPkg.publicFunction1('john','smith');
myPkg.publicFunction2();
Code language: JavaScript (javascript)
You may have noticed a trailing ‘()’ at the end of our ‘package’. This is part of the anonymous function’s signature. That being the case we can pass whatever parameters in we like, just like in normal functions. For instance, if you need jQuery in your package you can pass it in (and even ‘alias’ it to $ like normal):
var myPkg = (function($) {
// Package contents here!
return ({
functionName: function() {
// public function contents here.
}
});
})(jQuery));
Code language: JavaScript (javascript)
Now jQuery functions can be accessed via their $ alias inside the ‘package’ just like they can everywhere else!
Global Packages
We can extend the ‘globalness’ of the closures approach by attaching our host variable to the window object and then declaring functionality that way. Global variables are, technically speaking, attached to the window object anyway so it’s just a bit neater and not bad practice.
(function(myPkg, $) {
// Private variables can be defined just like before.
var outsideWorldCannotSeeMe = 0;
// ... So can private functions.
function privateFunction() {
}
// And... Declaring public functions is now easier and more readable.
myPkg.myThingToDo: function() {
// public function contents here.
};
})(window.myPkg = window.myPkg | { }, jQuery)); // Create new myPkg variable if it isn't already defined (and if it is - add to it.)
// Use is just as before...
myPkg.myThingToDo();
// or even...
window.myPkg.myThingToDo();
Code language: JavaScript (javascript)
Another handy feature of this last approach is that we can spread functionality across multiple JS files. Let’s say we wanted to package all our company-specific JavaScript utility functions and our company was called ‘Foo’. Then we could have multiple files defining closures like this:
(function(foo, $) {
// functionality here!
})(window.foo = window.foo | { }, jQuery);
Code language: JavaScript (javascript)
The first JS file that references foo will cause it to be created as a global variable (window.foo) and then when subsequent files are loaded, they’ll access the existing foo object (window.foo) and add their own bits and pieces to it. This means we can organise our JS files by topic, etc. (popups, formatting, validation, etc.) and then bundle them into a single top-level object (foo) to make it easier when using them. We could even provide additional nesting to ‘namespace’ them (although, strictly speaking, this isn’t namespacing but just a nesting that improves readability.)
// JS File 1 - Contents...
(function(foo, $) {
return (
popups: function() {
return (
error: function(message) {
// code to display the error dialogue box.
},
info: function(message) {
// code to display the informational dialogue box.
}
);
}
);
})(window.foo = window.foo | { }, jQuery);
// JS File 2 - Contents...
(function(foo) {
return (
formatting: function() {
return (
poundSterling: function(text) {
// code to format value with UK Pound symbol and
// numeric value to 2 decimal places (pounds and pence.)
}
);
}
);
})(window.foo = window.foo | { });
// Calling functions in the host web page...
try {
foo.formatting.poundSterling('not a number');
} catch (e) {
console.log(e);
foo.popups.error('Wah! It all went wrong!');
}
Code language: JavaScript (javascript)
As you can see, we can now structure our JS files by functional set and expose them in a meaningful way that can be consumed by in-page JavaScript (or by other JS files.)
NOTE: Use caution with the multi-file approach though. Web browsers only download a limited number of files at the same time – normally Web developers concentrate on minimising the number of files that need to be downloaded, not increasing them. This example was just to show what could be done.
Javascript Classes
Javascript classes were introduced in ECMAScript 2015 (ES6). Classes can be defined, in a similar way to high-level programming languages, as follows:
class SomeName {
constructor() { ... }
someMethod(someVal) { ... }
anotherMethod(firstVal, secondVal) { ... }
}
Code language: JavaScript (javascript)
The constructor and methods can all have zero or more parameters.
In earlier versions of JavaScript an approximation of a class can be implemented using closures. Let’s look at a worked example:
// ES6 code declaration of the class.
class Task {
#name = '';
#from = null;
#until = null;
#assignee = null;
constructor(name, from, to) {
this.#name = name;
this.#from = from;
this.#until = to;
}
static defaultDurationInHours = 1;
get name() { return this.#name; }
get from() { return this.#from; }
get until() { return this.#until; }
get assignedTo() { return this.#assignee; }
assign(name) { this.#assignee = name; }
}
Code language: JavaScript (javascript)
The above class defines some private variables, parameterised constructor, read-only properties, a object method, and a static property. This makes it fairly complex in terms of content, but we can still easily replicate this in ES5 JavaScript:
// ES5 code equivalent approximating the class...
var Task = (function () {
function Task(name, from, to) {
this.privateName = name;
this.privateFrom = from;
this.privateUntil = to;
this.privateAssignee = null;
}
Task.prototype.assign = function (name) {
this.privateAssignee = name;
};
Object.defineProperty(Task.prototype, 'name', {
get: function () { return this.privateName; },
enumerable: false,
configurable: true
});
Object.defineProperty(Task.prototype, 'from', {
get: function () { return this.privateFrom; },
enumerable: false,
configurable: true
});
Object.defineProperty(Task.prototype, 'until', {
get: function () { return this.privateUntil; },
enumerable: false,
configurable: true
});
Object.defineProperty(Task.prototype, 'assignedTo', {
get: function () { return this.privateAssignee; },
enumerable: false,
configurable: true
});
return Task;
}());
Task.defaultDurationInHours = 1;
Code language: JavaScript (javascript)
Although the ES6 model is cleaner and more readable, an immediate problem with it at the time of writing is compatibility. Internet Explorer is still in significant use and it doesn’t support ES6 at all. While a lot of other major browsers (Chrome, Firefox, Opera, Safari, etc.) do support ES6 they do so to greater or lesser extents and most do not fully support the standard. As such it is probably wise (at the time of writing) to use the ES5 approach for maximum compatibility at the expense of code readability.