Programs are meant to be read by humans, only incidentally by computers to execute
Donald KnuthAlways code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
— Kyle Richter (@kylerichter) December 15, 2010If there is a feature of the language that is sometimes problematic, and if it can be replaced with another feature that is more reliable, then always use the more reliable feature.
Douglas Crockford// any number that isn't zero evaluates to TRUE var a = [1, 2, 3]; while (a.length) { // do something with array }
// any string that isn't empty evaluates to TRUE var s = "This is interesting"; if (s) { // while s.length is a postive number, // we can just evaluate the string. }
// any object reference that isn't null or undefined // evaluates to TRUE var o = {}; if (o) { // 'o' exists, let's do something with it }
// an example ajax success callback // receiving (parsed) JSON data function success(data) { // check if data was returned as array if (data && data.length) { // do something with the array } else if (data) { // only one object } }
// "zero" (0) evalues to FALSE var elements = $('#Container > div'); if (!elements.length) { // There are no elements in this jQuery object }
// An empty string ('') evaluates to FALSE var s = ''; if (!s) { // Do something with the empty string }
// "undefined" evaluates to FALSE var data; if (!data) { // data is not defined ('undefined' by default) }
// "null" evaluates to FALSE function Widget() { this.element = null; } var w = new Widget(); if (!w.element) { // element is null }
// Because of "false", we have "coalesce" (function() { // CSN is the root namespace // If it hasn't already been defined, do so // Thanks to the short circuit "or", // the left side will evalute to FALSE // and assign an empty object to the // global "CSN" and the local variable. var CSN = window.CSN || (window.CSN = {}); }());
(function($, CSN) { // define hidden objects and variables here // define functions, classes here that are part of namespaces // define jQuery plugins }(jQuery, (window.CSN || (window.CSN = {}))));
(function(CSN){ // "CSN" is the root namespace // Check if the "Utils" namespace has been defined // and then use an alias variable to ease typing var utils = CSN.Utils || (CSN.Utils = {}); // Add public functions to CSN.Utils utils.format = function(s) { // defines CSN.Utils.format() }; }((window.CSN || (window.CSN = {}))));
// You need to record the index of each element var element, inputs = document.getElementById('Module').getElementsByTagName('input'); for (var i, j = inputs.length; i < j; i++) { element = inputs.eq(i); // Retain the value of "i" for each iteration // By passing the value into this IIFE (function(i) { element.on('focus', function() { // do something with "i" $(this).data('index', i); }); })(i); }
// You need to record the index of each element // Even better $('#Module input').each(function(i, element){ // Each index is recorded $(element).data('index', i); });
function Widget(element) { this.element = element; } Widget.prototype.change = function() {}; Widget.prototype.init = function() { this.element.on('click', function() { // In here, "this" refers to the element }); }
function Widget(element) { this.element = element; } Widget.prototype.change = function() {}; Widget.prototype.init = function() { var that = this; this.element.on('click', function() { // In here, "this" refers to the element // But we can use "that" // to refer to the containing object that.change(); }); }
'use strict'; // Using Function.bind() function Widget(element) { this.element = element; } Widget.prototype.change = function() {}; Widget.prototype.init = function() { var that = this; this.element.on('click', function(ev) { // In here "this" refers to // the containing object this.change(); }.bind(this)); }
// Function currying JsonpService.postAjax = function (aspect, canPipe, itemCountKey) { return function (data, error, msg) { var newCount; if (!error) { newCount = parseInt(data[itemCountKey], 10); if (!isNaN(newCount)) { this.itemCount = newCount; } if (canPipe) { data = this.pipe("out", data); } this.notify(aspect, data); if (this.itemCount >= this.maximum) { this.notify("full", this.itemCount); } } else { this.errorHandler(error, msg); } }; }; JsonpService.prototype.create = function (data) { var handler = JsonpService.postAjax("create", true, "NewCount"); // wrap in jQuery.proxy to improve lexical scope // and pass the handler to jQuery.ajax };
(function($) { 'use strict'; // "ToolboxWidget" class is hidden from outside world function ToolboxWidget(element) { this.element = element; // Define other properties } ToolboxWidget.prototype.init = function() { // Initialize state // Invoke other setup methods }; $.fn.toolbox = function(options) { options = $.extend({}, $.fn.toolbox.defaults, options); this.each(function() { // The ToolboxWidget handles the state // of the object. We're reducing the // number of DOM interactions to // improve performance. var w = new ToolboxWidget($(this)); w.init(); // do more with widget w.data('widget', w); }); return this; }; $.fn.toolbox.defaults = {}; }(jQuery));
<body> <!-- generated HTML here --> <!-- scripts at bottom of page for performance --> <script src="./scripts/toolbox-widget.js"></script> <!-- define entry point for Toolbox Widget, with configuration --> <script> (function($){ $("#Toolbox").toolbox({searchUrl:"/results/{0}"}); }(jQuery)); </script> </body>
<body> <!-- generated HTML here --> <!-- scripts at bottom of page for performance --> <script src="./scripts/app.js"></script> <!-- set up, with configuration --> <script> (function($){ CSN.App.init({startPage:2}); }(jQuery)); </script> </body>
function someMethod() { return { name: "Peter" } }
function someMethod() { return { name: "Peter" }; }
if (a > 10) doThis(); else doThat();
if (a > 10) doThis(); else doThat(); doSomethingElse();
if (a > 10) { doThis(); doSomethingElse(); } else { doThat(); }
// typeof "ABC" == "string" // typeof 2134 == "number" // typeof {} == "object" // typeof function() {} == "function" // typeof null == "object" // typeof [] == "object" // typeof undefined == "undefined"
var a = "123"; if (a == 123) { // TRUE // a is "coerced" into a number } var b; if (b == null) { // TRUE // "undefined" is coerced into being "null" }
var a = "123"; if (a === 123) { // a HAS to be a number for this to be TRUE } var b; if (b === null) { // b MUST have null assigned to it to be TRUE } // even better: if (!b) { // use FALSY rule }
(function() { 'use strict'; // OK, define module // Any variable not defined will throw an error }());
(function() { 'use strict'; var a = [1, 2, 3]; a.forEach(function(item) { // do something on each array element }); }());
(function() { 'use strict'; var person = { firstName: 'Peter', lastName: 'Berry', age: 41, lives: 'Brunswick' }; // Object.keys returns an array of properties var properties = Object.keys(person); // We can then use forEach to enumerate // This code will output the value of each property properties.forEach(function(p){ console.log(person[p]); }); }());
jQuery("body").on('click', function() { a = a + 1 if (a == 1) alert('Hello World); })
jQuery("body").on('click', function() { a = a + 1 if (a == 1) alert('Hello World); })
{ "name": "Peter","description":"has written some dodge code in the past", "flagged":true, "age":41}
{ "name": "Peter","description":"has written some dodge code in the past", "flagged":true, "age":41}
Code in a manner that another developer, who is not familiar with JavaScript, can comprehend the intent of the code.
Handling events and passing to nested functions is messy - "callback hell"
Promises has a fluent API
// Nested callbacks http.get(url.parse("http://example.org/"), function (res) { console.log(res.statusCode); // maybe 302 http.get(url.parse(res.headers["location"]), function (res) { console.log(res.statusCode); // maybe 200 }); });
// Promises httpGet(url.parse("http://example.org/")).then(function (res) { console.log(res.statusCode); // maybe 302 return httpGet(url.parse(res.headers["location"])); }).then(function (res) { console.log(res.statusCode); // maybe 200 });
function makeDo(arg) { if (arg.isValid) { let a = arg.value; // do something with a // "a" is in block scope } }
Hosted by: Alastair Burrowes