Text

Asynchronous messaging

JavaScript runs in a single thread inside browsers. When the thread is busy, asynchronous events like user actions or XHR responses get queued up and only get processed when the currently running JavaScript execution thread becomes idle.

Suppose you want to fire off an event but don’t want the code for handling that event to be run immediately:

if (!this.fmt.test(this.value)) {
    this.fireEvent("invalid"); // Synchronous processing!
    this.markInvalid(true);
}

You can use window.setTimeout to bring asynchronousity to the firing and processing of the event:

if (!this.fmt.test(this.value)) {
    var that = this;
    setTimeout(function () {
        that.fireEvent("invalid");
    }, 1);
    this.markInvalid(true);
}

If you use a 0 millisecond timeout, some JavaScript engines may short-circuit it to an immediate functional call, beating the purpose of using setTimeout. 1 millisecond allows a short-circuit-free minimum delay. Note that some engines may have a minimum timer resolution of 10 milliseconds or so.

Text

Know when it is no longer JSON

Do you ever call your variables that get populated from a JSON string something with “json” in them?

function processData(json) {
    // if (json.accountType == "savings") ...
}

Realize that “JSON” only describes the format of the data you’re fetching through XHR or <script>. It is a string representation of an object. When you’re in the JavaScript domain, and about to process the parsed result of the JSON string, leave “json” behind:

function processData(obj) {
    // if (obj.accountType == "savings") ...
}
Tags: beginner style
Text

Rounding with significant figures

A function for rounding a decimal number to a given number of significant figures (or digits):

function sigFigs(n, sig) {
    var mult = Math.pow(10,
        sig - Math.floor(Math.log(n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
}

alert(sigFigs(1234567, 3)); // Gives 1230000
alert(sigFigs(0.06805, 3)); // Gives 0.0681
alert(sigFigs(5, 3)); // Gives 5
Text

Parsing query string parameters into a collection

Here’s a utility function for parsing query parameters:

function getQueryParams(qs) {
    qs = qs.split("+").join(" ");
    var params = {};
    var tokens, re = /[?&]?([^=]+)=([^&]*)/g;

    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])]
            = decodeURIComponent(tokens[2]);
    }

    return params;
}

//var query = getQueryParams(document.location.search);
//alert(query.foo);

A nice things is that it’s decoupled from document.location.search.

Text

Parsing ISO 8601 UTC dates

Here’s a concise implementation for parsing UTC date strings in ISO 8601 format into Date objects in the local time zone.

function parseIsoDate(s) {
    var tokens = /(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)\.(\d+)/
        .exec(s).slice(1);
    tokens[1] -= 1;
    return new Date(Date.UTC.apply(null, tokens));
}

The new Date(Date.UTC.apply(null, tokens)) trick allows the direct usage of an array of date components for the construction of a new Date instance.

Text

String formatter

Here’s a basic string formatter that takes in a format string and a variable number of arguments:

// Format string may contain variable references in the form "{i}"
// where i is the variable index
function format(fmt) {
    return fmt.replace(/\{(\d+)\}/g, function (s, i) {
        return arguments[i];
    });
}

// Usage:

var usercnt = 45, groupcnt = 3;

format("Found {1} users and {2} groups", usercnt, groupcnt);
// Returns "Found 45 users and 3 groups"

Similarly, object property names could be used:

// Format string may contain variable references in the form "{n}"
// where n is the variable name
function format(fmt, object) {
    return fmt.replace(/\{(\w+)\}/g, function (s, n) {
        return object[n];
    });
}

// Usage:

var results = {
    usercnt: 45,
    groupcnt: 3
};

format("Found {usercnt} users and {groupcnt} groups", results);
// Returns "Found 45 users and 3 groups"
Text

Reversing a string

JavaScript doesn’t have a reverse() method for strings but has one for arrays. The trick is to convert a string to an array, reverse the array and combine the array back into a string:

var s = "Hello World!";

var reversed = s.split("").reverse().join("");
// "!dlroW olleH"
Text

Appending an array of items to an array

Suppose you already have some items in an array and you want to append those items to a target array. You can use the concat method to create a new array that is the concatenation of the two arrays and replace the target array with the result:

var items = [ 3, 5, 7 ];
target = target.concat(items); // new instance!

You can avoid replacing the array with a new instance every time you need to append new items to it by using the push method. One thing to note is that push accepts multiple arguments and we can apply the new item array as arguments to push directly:

Array.prototype.push.apply(target, items);
// Equivalent to target.push(3, 5, 7)
// -- if the items weren't already in an array
Text

Properly clearing properties

If you want to clear a property of an object, simply setting it to undefined won’t always cut it, based on how you will access/test the property later on:

// The setup
var obj = {
    prop: 1
};

// Clear property value
obj.prop = undefined;

The property is still attached to the object as a property and can be enumerated:

for (var key in obj) {
    // Will iterate through "prop"
}

typeof obj.prop == "undefined" // true
obj.hasOwnProperty("prop") // true -- it's still there!

To completely eliminate a property, you need to delete it:

delete obj.prop;

for (var key in obj) {
    // Won't iterate through "prop" anymore
}

typeof obj.prop == "undefined" // true
obj.hasOwnProperty("prop") // false -- it's gone completely!