Category Archives: JavaScript

Extending JavaScript Built-ins

Credit Martin Burns
Credit: Martin Burns

One should neither split infinitives nor end sentences with prepositions. These statements are examples of prescriptive grammar. Prescriptive grammar means rules invented by self-appointed experts who presume to tell others how they should speak if they don’t want to sound like louts. As far as I can tell, the origin of these prescriptions is that you couldn’t split infinitives or strand prepositions in Latin. Except we speak English and English accommodates “to boldly go” just fine and if we were to ask someone “About what are you talking?” they would be unlikely to compliment us on the quality of our speech.

The Internet is full of self-appointed experts who presume to tell others how to program in a similarly prescriptive way. One of the prescriptions that you may or may not be aware of is that one should never extend the built-in JavaScript classes (i.e. String, Array, Date, etc.). This Stack Overflow post is a good example of the controversy complete with huffing and puffing and stern warnings against the evils of such a filthy habit. Yet the ability to extend the behaviour of classes without subclassing is a core feature of JavaScript, not a bug, so a prescription against such a useful ability had better have a really good rationale (and no, MDN, fulmination is not a valid argument). The arguments against go something like this:

  • The method might be implemented in a future standard in a slightly different way
  • Your method name appears in for...in loops
  • Another library you use might implement the same method
  • There are alternative ways of doing it
  • It’s acceptable practice for certain elites but not for the unwashed masses
  • A newbie programmer might be unaware that the method is non-standard and get confused.

The retort to that last argument is “git gud”, while the retort to the last but one is something rather more robust. We’ll examine the other arguments in turn.

Implemented in a Future Standard

It might happen, particularly if the functionality is obviously useful. I started writing JavaScript early in 2005 and it didn’t take me long to get fed up with doing this:

var a = "...", s = "...";
...
if (a.substr(0, s.length) === s) {
   // a starts with s
}

The obvious solution was to extend the String class:
String.prototype.startsWith = function(s) {
   return (this.substr(0, s.length) === s);
};

This allowed me to express myself rather more clearly:
if (a.startsWith(s)) {
   ...
}

This is obvious functionality implemented in an obvious way. No, my implementation didn’t test for pathological input but then I never fed it pathological input so it didn’t matter. Sometime around 2012, browsers containing a native implementation of startsWith started appearing and the only thing that needed changing was a test for the presence of the method before stomping over it. Otherwise, despite the addition of a feature-in-search-of-a-use-case (a start position other than 0), the official implementations behaved identically to my venerable extension.

For argument’s sake, let’s say I’d called the method beginsWith. The fix would take longer to type than to apply:

$ sed -i -e 's/beginsWith/startsWith/g;' *.js

Even if I’d been stupid enough to do something like return 0/-1 rather than true/false, fixing up my uses of startsWith to use a different return type would have been the work of a few minutes. We call this refactoring which means that the argument in favour of possible future implementations is actually an argument against refactoring which is no argument at all.

for…in Pollution

The problem here is that your method name appears in the enumerable properties of an object but this is actually a non-issue. Leaving aside the fact that it has been possible for some years to ensure that your method is not enumerable in the great majority of browsers in the world, would you ever enumerate the properties of a String or Date object? Hint: there are no enumerable properties. Furthermore, if you enumerate over an Array with a for...in loop, you’re doing it wrong.

Implemented by Another Library

The problem here is that the last library included wins and if utility library A behaves differently to utility library B, code may break. But again, this is something of a non-issue if certain safeguards are observed: test for the existence of an existing method and implement obvious functionality in an obvious way. If anything, this is an argument against using the monolithic jqueries of the world in favour of micro frameworks, since micro frameworks tend not to do a 1001 things that you don’t know about.

It’s Unnecessary

True, inasmuch as there is always more than one way to do anything. The question is: are alternatives better? Let’s say that I want a function to shuffle an Array. The function might look like this:

function shuffle(a) {
    var l = a.length, c = l - 1, t, r;
    for (; c > 0; --c) {
        r = Math.floor(Math.random() * l);
        t = a[c];
        a[c] = a[r];
        a[r] = t;
    }
    return a;
}

For the interested, this is the Fisher-Yates algorithm. How are we going to make this function available to our application? We can reject one possibility - subclassing Array - right away. The reason is that arrays are almost always instantiated using the more expressive literal notation:
var a = [1, 2, 3],   // like this almost always
    b = new Array(); // like this almost never

This makes using a MyExtendedArray class unfeasible - the overhead would simply be too great. The same applies to theoretical subclasses of String and Number.

Using a procedural approach is doable but we now come up against the problem of namespacing. As written, the identifier "shuffle" is placed into the global namespace. This isn't as fatal as some would have you believe if it's for private consumption. However, if you plan to create a library for consumption by others you should avoid using the global namespace because collision with identically named entities is a non-negligible risk. One could imagine, for example, another "shuffle" function that works on a "DeckOfCards" object or a "Songlist". Utility functions are problematic because the namespace isn't obvious. One could choose something like "ArrayUtils" but then you're liable to be competing with everyone else's ArrayUtils. So you might end up doing this:

if (!("CCWUtils" in window)) {
    CCWUtils = {};
}
CCWUtils.Array = {
    shuffle: function(a) {
        ...
    }
};

...

var cards = ["AS", "2S", "3S", ... , "JC", "QC", "KC"];
CCWUtils.Array.shuffle(cards);

Remember that we're doing it this way because we believe that adding a "shuffle" method to the native Array class is somehow sinful. If that feels like the tail wagging the dog, compare the sinful approach:
if (!("shuffle" in Array.prototype)) {
    Array.prototype.shuffle = function() {
        ...
    };
}

...

var cards = ["AS", "2S", "3S", ... , "JC", "QC", "KC"];
cards.shuffle();

To my eyes, cards.shuffle() is both more idiomatic and more elegant. Namespacing isn't a problem and I take care to play nicely with any existing shuffle method.

Doing it Right

I believe that extending built-in classes is a valid practice but there are some guidelines that you might follow:

  • Add useful functionality. For example, the concat method of String objects implements the same functionality as the + operator. Don't do something similar
  • Use an obvious name and implement obvious functionality
  • Be careful to avoid overwriting a method with the same name
  • If possible, ensure that your method is non-enumerable, if only to silence critics who might otherwise complain that you're polluting their for...in loops
  • Take some pains to ensure that your method behaves like other methods. For example, methods of built-in objects are typically implemented generically and mutator methods (methods that modify the object) typically return the mutated object as well.

With that in mind, here is the complete shuffle extension:

(function() {
    "use strict";
    var _shuffle = function(a) {
        if (null == a) {
            throw new TypeError("can't convert " + a + " to an object");
        }
        var _a = Object(a), len = _a.length >>> 0, c = len - 1, t, r;
        for (; c > 0; --c) {
            r = Math.floor(Math.random() * len);
            // Swap the item at c with that at r
            t = _a[c];
            _a[c] = _a[r];
            _a[r] = t;
        }
        return _a;
    },
    obj = Array.prototype, mName = "shuffle",
        m = function() { return _shuffle(this); };
    if (!(mName in obj)) {
        try {
            Object.defineProperty(obj, mName, {
                enumerable : false,
                value : m
            });
        }
        catch(e) {
            obj[mName] = m;
        }
    }
})();

Note the following:

  • Lines 4-6: Following other Array methods, raise a TypeError if passed undefined or null. And yes, that is == rather than === since I don't care to distinguish the two
  • Line 7: Our method can work generically on array-like objects (objects with a length and numeric property names) and it won't barf if passed a primitive value. You can pass non-Array objects to the method by invoking it as Array.prototype.shuffle.call(obj). Note, however, that a TypeError will be raised if the method is passed an immutable object, such as a String. That is also true of, say, reverse so it's not a problem
  • Line 15: Our method returns the mutated Object in the manner of similar methods such as sort and reverse
  • Line 17: Use the obvious name "shuffle". If we used something like "$shuffle" to ensure that we didn't conflict with a future implementation, we wouldn't automatically benefit from the native implementation. As it is, if "shuffle" ever becomes a standard method on Array, our extension simply becomes a shim
  • Line 19: Don't overwrite an existing method
  • Lines 21-24: This is how you ensure that the new method is not an enumerable property
  • Line 27: Fallback position for the off-chance that our code is running in Internet Explorer <= 8 or something similarly inadequate.

But Object.prototype is Forbidden, Right?

I said earlier that forbidding the use of a useful feature needed a good rationale. Well, here goes. Imagine that I wanted a method to count the number of properties of an Object and I implemented it like this:

Object.prototype.count = function() {
    var p, ret = 0;
    for (p in this) {
        if (this.hasOwnProperty(p)) {
            ++ret;
        }
    }
    return ret;
};

The problem is that Object is a first-class data type used to store key-value pairs which means that I can also do this:
var stat = {
    value: 1,
    count: 4   // Oops! count method is now shadowed
};

Rather than adding value, my count method has stolen a perfectly good property name. Even if we think we can do what we want by picking really obscure method names (breaking the "obvious" guideline in the process), Object is the base class of everything and the practice is simply hazard-prone. Illustratively, adding methods directly to Object.prototype breaks the "behaves like other methods" guideline as well, since most Object methods are static:
var a = 1;
...
if (Object.is(a, 1)) {
    // Not "if (a.is(1))"
}

So, yes, Object.prototype is forbidden.

Erm, What About "Host" Objects?

By "host" objects, we mean the objects that the browser makes available to your script that represent the visible and not-so-visible parts of your user interface: Document, Element, Node, Event and so on. These were the subject of an essay some years ago. Most of the issues considered are no longer really issues (applet elements, anyone?) and now this is a reasonable strategy:

if (!("Element" in window)) {
    // Don't try and do anything at all
}

With that in place, I can't see that the sky would fall if you did something like this:

Element.prototype.show = function(style) { // e.g. "inline-block"
    style = style || "";
    this.style.display = style;
};
Element.prototype.hide = function() {
    this.style.display = "none";
};

A possible problem might be one of scope. The behaviours that a String object doesn't have that you wish it did are distinctly finite: while you might want it to return a reversed copy of itself, you're probably not hankering for it to calculate a SHA256 hash of itself. The behaviours that we might want to add to objects that represent interface elements are not so limited. For example, we might want a method to set colours. Does our setColor method take two arguments and set the background colour as well? Or does it simply set the foreground colour, leaving the background colour to be specified by a call to setBackgroundColor? What about a method to set position and z-order? You'll quickly find yourself in danger of violating both the "useful" and "obvious" guidelines.

I'm a great believer in the Unix philosophy of doing one thing well. User-interface toolkits have a bad habit of trying to do flipping everything. My personal feeling is that extending interface objects is a bit like pulling a thread on your jumper: at some point you're going to wish you hadn't started. But if it works for you who am I to say you mustn't?

Conclusions

TL;DR: my views on extending built-in classes are:

  • Array, String, Number, Date: Yes; apply common sense
  • Object.prototype: Seriously, no
  • "Host" objects: not to my taste, but if it floats your boat...

What’s in a Number?

Credit: Jorge Franganillo
Credit: Jorge Franganillo

If we program in a low-level language like C, we have access to all sorts of numeric types of various sizes from unsigned char to long double. In JavaScript we have just the one: the IEEE 754 double precision floating point number (double for short). If we are to be limited to just the one number type, this is a pretty good one: it can represent whole numbers, fractional numbers, tiny numbers, enormous numbers and infinity.

A double is a 64-bit value arranged thus:

  • 1 sign bit
  • 11 bits of exponent
  • 53 bits of significand

If you’re sharp, you’ll notice that this sums up to 65 bits. This is possible because the numbers are normalized. As to what “normalized” means, consider the difference between 1.25×103 and 125×101. They both represent the same number but the first is normalized while the second is a bit weird. In base 10, the first digit of a normalized number is between 1 and 9 inclusive. In binary it’s always1. Since it’s always 1, we can leave it out without losing information. Hence, we get 53 bits of precision despite only having 52 bits to play with. An 11-bit exponent gives a range of 0-2047. Since we need to be able to represent small numbers, the actual exponent is obtained by subtracting 1023 from this, giving a range of -1023 to 1024. As we’ll see, the maximum and minimum exponent values are reserved so the usable range is -1022 to 1023.

In C it’s easy to get at the internals of a double:

#include <stdint.h>
...
double pi = 3.141592653589793;
uint64_t *p = (uint64_t *) &pi;
/* Twiddle bits through *p */
...

In JavaScript, we can’t access the internals directly, but a little bit of trickery opens them right up. Let’s see whether this is possible. Tell me, computer, will you allow me to peek inside the internals of a double?

Assuming that the required runtime support is available, the following function will split a double into its constituent parts as human-readable strings:

window.showNum = function(n) {
    var buf = new ArrayBuffer(8),
        dv = new DataView(buf);
    dv.setFloat64(0, n, true);
    var m = dv.getInt32(0, true),
        i = 0, j = 1, p = "", ret = {};
    for (; i < 64; ++i, j <<= 1) {
        if (i === 32) {
            // Done with the first half
            j = 1;
            m = dv.getInt32(4, true);
        }
        else if (i === 52) {
            // Built up the significand
            ret.m = p;
            p = "";
        }
        else if (i === 63) {
            // Built up the exponent
            ret.e = p;
            p = "";
        }
        if (m & j) {
            p = "1" + p;
        }
        else {
            p = "0" + p;
        }
    }
    // Set the sign bit
    ret.s = p;

    // Calculate the represented value as a
    // base-2 exponential value
    var sig = 1, f = 0.5, e = -1023;
    for (i = 0; i < 52; ++i, f /= 2) {
        if ('1' === ret.m.charAt(i)) {
            sig += f;
        }
    }
    j = 1;
    for (i = 10; i >= 0; --i, j <<= 1) {
        if ('1' === ret.e.charAt(i)) {
            e += j;
        }
    }
    ret.t = sig + "e" + e;
    if ('1' === ret.s) {
        ret.t = '-' + ret.t;
    }

    return ret;
};

Here’s how it works. An ArrayBuffer is a low-level generic data container that behaves roughly like a byte array. We get at the internals of the buffer by overlaying either a typed array (such as Int32Array) or a DataView. I chose a DataView because then I don’t have to worry about endianness. The true arguments to setFloat64 and getInt32 means “little-endian, please”. We stick the double into the buffer and then access it as two 32-bit integers. We may not be able to get at the bits in a double from JavaScript but we can do bitwise operations on an int. Had we used false as the endianness flag, we’d have to read out the ints in reverse order. Without a DataView, I would have to do some additional work to determine the endianness of your system. When we’re done calculating the bit strings, we build up a base-2 exponential representation that’s a bit more human-readable. The bits of the significand are all fractional with the first bit representing ½, the second bit ¼ and so on. The exponent is calculated working right-to-left along the bit string, remembering to take the bias of 1023 into account. The return property for the significand is “m” which stands for mantissa. Technically, this is wrong because the strict definition of “mantissa” is the fractional part of a logarithm. However, “s” is already used for the sign so “m” it is.

Let’s try it out. Tell me, computer, what does 1 look like internally?

That’s not a very interesting number apart from the exponent pattern which shows the 1023 bias. Tell me, computer, what does -√2 look like internally?

Limits

Let’s have a look at the limits of what is representable. Tell me, computer, what does the largest absolute value that you can handle look like internally?

In base 10, this is 1.7976931348623157×10308. What about the smallest?

That last one may be surprising if you recall that I said the minimum usable exponent was -1022. This value is denormalized and is, in fact, the smallest denormalized value. This may (or may not) be familiar to C++ programmers as std::numeric_limits::denorm_min. An exponent of -1023 signfies a subnormal number and the signficand must be interpreted as 0.f rather than 1.f. Therefore, the significand of the smallest number represents 2-51. When you add the exponents together, you get a value of 2-1074 which is the absolute limit of representability that is not zero. Using bits from the significand as additional exponent bits allows for gradual underflow at the cost of precision – at the limit, there is only a single bit. In base 10, it translates (very approximately) to 5×10-324.

The more familiar value to C/C++ programmers is DBL_MIN. Tell me, computer, what does DBL_MIN look like internally?

In base 10, this is 2.2250738585072014×10-308.

Infinity and NaN

A value with all 1s in its exponent signifies an abnormal condition. The first condition is overflow. Tell me, computer, what does the product of 10155 and 10154 look like internally?

This value is commonly represented as Infinity. The sign bit can be set and this represents minus infinity. The characteristic of the two infinities is that all exponent bits are 1 and all significand bits are 0.

The second condition is where the numeric representation of a value is undefined. Tell me, computer, what does 0/0 look like internally?

This value is commonly represented as NaN (aka, not a number). The characteristic of NaN is that all exponent bits are set along with 1 or more significand bits.

Zero

If the significand in a double is to be interpreted as 1.f, there is no possible representation of zero since there is no y such that 1.f×2y = 0. The solution is to reserve a pattern to represent 0. From the representation of the smallest denormalized number above, you’d be correct in guessing that this pattern is all exponent bits set to 0 along with all significand bits. However, the sign bit can be set or unset which means that there are two zero values: 0 and -0. -0 will be the result, for example, of truncating a value between 0 and -1.

Epsilon

Although we can represent minuscule numbers by reducing the exponent, there is a hard limit to the fractional values that can be represented by adjusting the significand. Since a double has 52 fraction bits, this value may trivially (and precisely) be calculated as Math.pow(2, -52). This value is known as machine epsilon and is denoted by 𝜀. It is the smallest value for which the following inequality is true:
1 + \epsilon > 1
Assuming that your browser supports it, the machine epsilon value is in Number.EPSILON

Largest integer values

The width of the significand also determines the limits on the maximum size of a whole number that can be represented without loss of precision. The largest values have all significand bits set to 1 and the exponent set to 10000110011b (that is, 52). In other words, ±253 – 1. Note the qualifier “without loss of precision”. Larger integer values can be represented but not uniquely. To illustrate:

253 - 2 → 9007199254740990
253 - 1 → 9007199254740991
253     → 9007199254740992
253 + 1 → 9007199254740992

Assuming browser support, the largest integers that can be represented in a double are given by the MAX_SAFE_INTEGER and MIN_SAFE_INTEGER properties of Number.

Playing

Assuming you saw the answer “Of course” to the first question I asked the computer, you can type numbers into the following input and the component parts will be displayed in the box below. Large and small numbers can be entered using ‘e’ notation, for example, 1.23e-50. You can also type properties of Math and Number, such as PI, E, SQRT2, MAX_SAFE_INTEGER, EPSILON, etc.


Naive Implementations

Credit: The Guardian
Credit: The Guardian

With ES6, the JavaScript math library gained a level in badass with the addition of seventeen new functions. While I was polishing my UsefulJS library for publication I decided I’d spend a couple of fun evenings implementing shims for them since, if I want to calculate the hypotenuse, I do not want to have to do this:

var x = 3, y = 4,
    r = ("hypot" in Math) ? Math.hypot(x, y) :
        Math.sqrt(x*x + y*y);

The C++ documentation for hypot has an interesting statement in the notes:

POSIX specifies that underflow may only occur when both arguments are subnormal and the correct result is also subnormal (this forbids naive implementations).

By naive implementations, they mean something like this:

(function() {
    if (!("hypot" in Math)) {
        Math.hypot = function(x, y) {
            return Math.sqrt(x*x + y*y);
        };
    }
})();

As it happens, this wouldn’t be up to standard anyway since Math.hypot takes any number of arguments but that’s a detail irrelevant to this discussion. Since this is the formula for Pythagoras’s theorem, what’s naive about it? Tell me, computer, what is the hypotenuse when the two shorter sides are 10155 and 1?

That’s why it’s naive: even though the correct result (which is 10155) can be represented, there’s an overflow in the intermediate calculations that causes the wrong value to be returned. Moler and Morrison published a non-naive algorithm for calculating the hypotenuse in 1983. Not only does it avoid underflow and overflow in intermediate products, it also avoids taking a square root (which was presumably an attractive quality back then). Let’s give it a whirl:

var mm = function(x, y) {
    // Use abs values
    if (x < 0) {
        x = -x;
    }
    if (y < 0) {
        y = -y;
    }
    var tmp, r, s;
    // Ensure that x >= y
    if (x < y) {
        tmp = x;
        x = y;
        y = tmp;
    }
    do {
        tmp = y / x;
        r = tmp * tmp;
        s = r / (4 + r);
        x = x + 2 * s * x;
        y *= s;
    }
    // While y is significant
    while (1 + y > 1);
    return x;
};

Tell me, computer, what, according to the Moler-Morrison algorithm, is the hypotenuse when the two shorter sides are 3 and 4?

Damn and blast! Everyone knows that’s 5! Can we do better? Let’s rearrange the formula a little starting from the familiar form:
r = \sqrt{x^2+y^2}
The sum inside the square root can be expressed as:
x^2(1 + (y/x)^2)
Why should we care? Because we can take x2 outside the square root to give:
r = |x|\sqrt{1 + (y/x)^2}
As long as we ensure that x >= y, (y/x)2 will not overflow. It might underflow, but then the result is simply |x| which to all intents and purposes is correct. Let’s give it a try:

var hypot = function(x, y) {
    var tmp, r;
    if (x < 0) {
        x = -x;
    }
    if (y < 0) {
        y = -y;
    }
    if (x < y) {
        tmp = x;
        x = y;
        y = tmp;
    }
    if (!x) {
        // hypot(0, 0)
        return 0;
    }
    r = y / x;
    return x * Math.sqrt(1 + r * r);
};

The only gotcha here is to avoid the division 0/0 which would result in NaN, but otherwise it’s straightforward. Now tell me, computer, what is the hypotenuse when the two shorter sides are:

  • 3 and 4
  • 0 and 0
  • 10155 and 10155

Works like a charm! You may well ask whether there's any point in being able to calculate the hypotenuse of extremely large numbers. I can't see myself ever needing to do it yet I went to the trouble of making it possible. The reason is simple: pride. I do not want someone looking at my code and thinking "n00b!".

Several of the new Math functions, such as expm1 and log1p, can give the wrong result if they're not carefully implemented. Tell me, computer, does your Math library contain naive implementations?

If you're seeing "Dunno", your browser doesn't support ES6 Math functions. "Looks like it" means that the area hyperbolic sine (asinh) of 10-16 was given as 0. To machine precision, this should be 10-16. In fairness to the engineers, the deficiency probably lies in the underlying C libraries. "Not as far as I can tell" means that this particular Math function at least has been carefully implemented. The difference between 0 and 10-16 may seem trivial but it's a 100% loss of accuracy, an example of what is known as catastrophic cancellation.

As to how naive or not my own math code is, see for yourself! (Math code starts around line 1250).

I Know Where You Live

Credit: Hope Abrams
Credit: Hope Abrams

With a reasonable chance of success, I can obtain your location to a fair degree of accuracy. Let’s give it a go.

Obtaining your location...

Hopefully, you’ll see a table of scarily-accurate information rather than an error message. If the info is miles out (or even thousands of miles out) then you’re probably reading this at work.

IP addresses are not given out willy-nilly. They are assigned hierarchically: you are assigned an address by your ISP who buy blocks of addresses from a national registrar who has been given larger blocks of addresses by the big regional registrars (for example, ARIN in North America and RIPE NCC in Europe and most of Asia). These assignments are kept in a distributed database called the whois database. If you have a Mac OS X or Linux system, you can query the database yourself:

$ whois <IPADDRESS>

This gives you most of the information you see above. Other information may be obtained by various forms of data mining; for example, when you get a weather forecast for your home town, some organization now has a fair idea of which town is your home town.

Question: is the ability to locate you by your IP address a good thing, a bad thing or just a thing? I’d say the latter. It’s a necessary side-effect of how the Internet works. Data has to be routed from one host on the Internet to another. The problem of how to do this is only tractable because of the hierarchical block assignment of IP addresses. Connecting to a local exchange ties you down further to a fairly narrow radius. On the minus side, disreputable sites may make false promises of women in your area. On the plus side, an attempt to buy goods using your Amazon account from an IP address located in Russia will throw up a red flag.

Technical Details

I’m using a geolocation API provided by ip-api.com (yes, this is an endorsement – their service is excellent and their fair use terms are very generous). They provide a JSONP interface into their database. If you’re not familiar with JSONP, it’s a way to access third party webservices, taking advantage of the fact that a JSON-encoded object is valid JavaScript and that src attributes in script tags, unlike AJAX requests, are not subject to a same-origin policy. Typically, a JSONP URL will take a callback parameter in its query string and it’s output will be the encoded JSON object passed as a parameter to your callback function. Specifically, my code looks this:

<script>
window.geo = function(obj) {
    ...
};
</script>
<script src="http://ip-api.com/json/?callback=window.geo" defer></script>

Callback function details are as follows:

window.geo = function(obj) {
    var gEle = document.getElementById("geoinfo");
    gEle.innerHTML = "";
    // Map obj properties to human readable values
    var pM = ["IP address", "query",
        "Hostname", "reverse",
        "Country", "country", "Region", "regionName",
        "City", "city", "Postcode", "zip",
        "Latitude", "lat", "Longitude", "lon",
        "Organization", "org", "Error", "msg"],
        i, tbl = document.createElement("table"),
        tr, rowIdx = 0, td, cellIdx, n, prop;
    for (i = 0; i < pM.length; i += 2) {
        n = pM[i];
        prop = pM[i + 1];
        if (!obj[prop]) {
            continue;
        }
        tr = tbl.insertRow(rowIdx++);
        cellIdx = 0;
        td = tr.insertCell(cellIdx++);
        td.appendChild(document.createTextNode(n));
        td = tr.insertCell(cellIdx++);
        td.appendChild(
            document.createTextNode(obj[prop]));
    }
    gEle.appendChild(tbl);
    if ("success" === obj.status) {
        var mapCtr = document.getElementById("map");
        mapCtr.style.height = "250px";
        var ll = {lat: obj.lat, lng: obj.lon},
        map = new google.maps.Map(mapCtr, {
            center: ll,
            zoom: 13
        }),
        marker = new google.maps.Marker({
            position: ll,
            map: map
        });
    }
};

The latitude and longitude are fed into Google Maps (whose API is a whole lot easier to use than it is to sign up for) to visualize the data.

Obtaining location information from the browser

Depending on whether your browser supports the geolocation API, whether you click the “Get Location” button, whether you give permission for your location to be used and where you are, you should see accurate information below. This information is obtained from a variety of sources. If your device has a GPS chip, that will be used. Otherwise, something like Google’s map of wi-fi networks may be used to obtain your location by triangulation. If you’re not using wi-fi, then the accuracy will be less impressive.

The API is very easy to use. You basically define a success callback and an error callback and then pass them to navigator.geolocation.getCurrentPosition, like this:

gEle = document.getElementById("geoinfo2");
var pre = document.createElement("pre");
gEle.appendChild(pre);
if (!("geolocation" in navigator)) {
    pre.innerHTML = "Geolocation is unavailable";
    return;
}

var showGeo = function() {
    var locSuccess = function(pos) {
        var lat = pos.coords.latitude,
            lon = pos.coords.longitude,
            tbl, tr, td, rowIdx, cellIdx, mapCtr;
        gEle.innerHTML = "";
        tbl = document.createElement("table");
        rowIdx = 0;
        tr = tbl.insertRow(rowIdx++);
        cellIdx = 0;
        td = tr.insertCell(cellIdx++);
        td.appendChild(
            document.createTextNode("Latitude"));
        td = tr.insertCell(cellIdx++);
        td.appendChild(document.createTextNode(lat));
        tr = tbl.insertRow(rowIdx++);
        cellIdx = 0;
        td = tr.insertCell(cellIdx++);
        td.appendChild(
            document.createTextNode("Longitude"));
        td = tr.insertCell(cellIdx++);
        td.appendChild(document.createTextNode(lon));
        gEle.appendChild(tbl);
        mapCtr = document.getElementById("map2");
        mapCtr.style.height = "250px";
        showLocation(lat, lon, mapCtr);
    },
    locError = function(e) {
        pre.innerHTML = "";
        pre.appendChild(
            document.createTextNode(
            "Unable to obtain location information: " +
            e.message));
    };
    navigator.geolocation.getCurrentPosition(
        locSuccess, locError);
};
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Get Location"));
btn.onclick = showGeo;
pre.appendChild(btn);

The geolocation API can also give you periodic updates. See the
MDN documentation
for further information.



Rounding Numbers: How Hard Can It Be?

Rules for rounding half up
Credit: tes.com

How hard? Hard enough, apparently, that your computer gets it badly wrong. Tell me, computer, what is 1.015 rounded to two decimal places?

If you see “1.01”, you are using a standards-compliant browser. An eleven year old child knows that “1.01” is wrong and when a kid can see that something’s wrong, it’s just not good enough! So how hard can it be when you put your mind to it? Let’s see.

Algorithms

Before implementing a precise rounding algorithm, we need to figure out what we mean by rounding. For most cases, it’s simple: you just round towards the nearest digit. The tricky case is what to do with those pesky halves. Turns out there’s more than one way to handle them.

Round half towards positive infinity

This is the method we learn at school: 1.5 rounds up to 2. But what do we do about negative numbers? If we apply the round-half-up rule consistently we have to round them up too so that -1.5 rounds up to -1.

Round half away from zero

This is what we get if we apply the round-half-up rule symmetrically: positive numbers are rounded up to become more positive, while negative numbers are rounded down and become more negative.

Round half to even

The problem with the round-half-up algorithms is that they introduce a bias. What this means is that if you round a set of random numbers and take the average, it will not be the same as the average of the originals. This matters a lot in some applications: if you’re a major bank those half pennies mount up! The solution to this bias is to round down as often as you round up. In the case of round half towards even (aka banker’s rounding), halves are rounded to the nearest even digit so that 1.5 and 2.5 both round to 2 while 0.5 and -0.5 both round to 0.

Other algorithms

There are other algorithms which are (almost) never used. Round-half-down or round half to zero simply makes your results look consistently wrong. Round half to odd has the disadvantage that it doesn’t round to 0. Alternate rounding requires that we keep track of the last direction while stochastic rounding (randomly up or down) requires a reliable source of randomness which as any fule kno is hard!

Internet Explorer

If you see “1.02” above, you are probably using Internet Explorer. Presumably, some Microsoft engineer looked at the output from the specification and thought “that’s not good enough” as well.

Implementation

When reading the code snippets in this section, assume the following module wrapper:

(function(window) {
    "use strict";
    ...
})(this);

Which algorithm to use? We’ll give the programmer a choice:

var _ralgs = {
    HALF_UP : 0,
    AWAY_FROM_0 : 1,
    TO_EVEN : 2
};

We can note that a naive implementation – scale up, round, scale back down – isn’t going to cut the mustard. The reason for this is the finite precision of your computer hardware. Tell me, computer, what do you get when you multiply 1.015 by 100?

We can also note that rounding to n decimal places is not an arithmetic operation, it is a presentation operation. Therefore, our rounding algorithm is going to work on the string representation of the number, a bit like humans do. Like all Objects, numbers in JavaScript have a toString operation. The only question is, is it fit for purpose? Tell me, computer, what is the stringified form of 0.0000001?

Tarnation! Admittedly, I don’t have to work with very small numbers very often, but an algorithm that didn’t work in the general case would bother the heck out of me! Looks as though we’re going to have to start by implementing toString ourselves and before we can do that we have to write a function that will zero-pad a string. This really should be a standard method on String, but it’s not hard to do:

// Padding function
var _pad = function(s, padTo, padWith, right) {
    s = s + '';
    var pad = "",
        toPad = Math.max(padTo, s.length) - s.length;
    while (toPad) {
        if (toPad & 1) {
            pad += padWith;
        }
        toPad >>>= 1;
        if (toPad) {
            padWith += padWith;
        }
    }
    return right ? s + pad : pad + s;
};

Don’t be too alarmed reading that while loop. String concatenation is relatively expensive (because strings are immutable) so adding one character at a time is sub-optimal. Instead of doing n concatenations we do, at most, log2 n. Now we can re-implement toString:

// Stringifies numbers, paying attention to very large and very small quantities
var _toString = function(n) {
    var parts = n.toExponential().split("e"),
        mag = parseInt(parts[1], 10),
        _n = parts[0];
    parts = _n.split("."),
    var iPart = parts[0],
        dPart = parts[1] || "",
        sig, ret;
    if (n < 0) {
        iPart = iPart.substring(1, iPart.length);
        sig = '-';
    }
    if (mag > 0) {
        ret = iPart + dPart;
        if (ret.length < mag + 1) {
            // Pad to the right with zeroes
            ret = _pad(ret, mag + 1, '0', true);
        }
        else {
            // Need to insert the decimal place at the
            // right point
            iPart = ret.substring(0, 1 + mag);
            dPart = ret.substring(1 + mag, ret.length);
            ret = iPart;
            if (dPart) {
                ret += '.' + dPart;
            }
        }
    }
    else if (mag < 0) {
        mag = -mag;
        // 0.0 followed by mag-1 x '0' followed
        // by iPart + dPart
        ret = _pad("0.", mag + 1, '0', true) +
            iPart + dPart;
    }
    else {
        return _n;
    }
    if (sig) {
        ret = sig + ret;
    }
    return ret;
};

toExponential gives us a consistent string representation of the number which we can then split to obtain the signficand and exponent. Then it’s just a matter of zero-padding the significand accordingly and sticking the decimal point in the right place. Taking a minus sign into account when padding is bothersome so we remove it and restore it afterwards.

The next bit we have to implement is the function where we “increment” a string, propagating any carry left:

// The numeric value of the '0' character
var _zero = '0'.charCodeAt(0),
// For suppressing -0
_likeZero = /^0(?:\.0*)?$/,
// Numerically increments a string
_incStr = function(s, pos) {
    if (pos >= 0) {
        var p1 = s.substring(0, pos),
            p2 = s.substring(pos, pos + 1);
        if ('.' === p2.charAt(0)) {
            // Skip past '.'
            return _incStr(p1, pos - 1) + '.';
        }
        var d = s.charCodeAt(pos) - _zero + 1;
        if (d >= 10) {
            d -= 10;
            // Carry 1
            p1 = _incStr(p1, pos - 1);
        }
        p2 = String.fromCharCode(d + _zero);
        return p1 + p2;
    }
    // We've incremented off the left edge of the string
    // so do the final carry
    return '1' + s;
};

That’s the boilerplate done. Now we can implement our rounding functions. All take a number and the number of desired fractional digits as parameters. First up, half-up:

// Implementation of round to plus infinity (exact)
var _round2PlusInfinity = function(n, fd) {
   var s = _toString(Math.abs(n)),
       pos = s.indexOf('.');
   // _toString gives x or x.yyy not .yyy
   if (pos >= 1) {
       var nd = s.length, rpos = pos + fd + 1;
       if (rpos < nd) {
           var d = s.charCodeAt(rpos) - _zero,
               up = d >= 5;
           if (d === 5 && n < 0) {
               up = false;
           }
           if (up) {
               // Round up
               s = _incStr(s.substring(0, rpos),
                   rpos - 1);
           }
           else {
               // Simply truncate
               s = s.substring(0, rpos);
           }
       }
   }
   if (n < 0 && !_likeZero.test(s)) {
       s = '-' + s;
   }
   return s;
};

Here we see what that mystery _likeZero regex was for. For negative numbers, we get rid of a bothersome minus sign by working with the abs value. If a value rounds to 0 and we stick the minus sign back on the front, we’ll end up with “-0” which just looks weird. Round half towards even is similar with a little bit of added complexity in deciding whether we round up or down:

// Implementation of round half to even (exact)
var _roundTowardsEven = function(n, fd) {
    var neg = false;
    if (n < 0) {
        // Round half to even is symmetric
        neg = true;
        n = -n;
    }
    var s = _toString(Math.abs(n));
    var pos = s.indexOf('.');
    if (pos >= 1) {
        var nd = s.length, rpos = pos + fd + 1;
        if (rpos < nd) {
            var d = s.charCodeAt(rpos) - _zero, 
                up = d > 5;
            if (d === 5) {
                // Check the previous digit
                var c, _rp = rpos, _d;
                do {
                    c = s.charAt(--_rp);
                }
                while (c === '.');
                _d = s.charCodeAt(_rp) - _zero + 1;
                // Up if the previous digit will be even
                up = (0 === _d % 2);
            }
            if (up) {
                // Round up
                s = _incStr(s.substring(0, rpos),
                    rpos - 1);
            }
            else {
                // Simply truncate
                s = s.substring(0, rpos);
            }
        }
    }
    if (neg && !_likeZero.test(s)) {
        s = '-' + s;
    }
    return s;
};

Implementation of the final algorithm is a doddle:

// Implementation of round half away from zero
var _roundAwayFromZero = function(n, fd) {
    if (n >= 0) {
        return _round2PlusInfinity(n, fd);
    }
    var ret = _round2PlusInfinity(-n, fd);
    if (!_likeZero.test(ret)) {
        ret = '-' + ret;
    }
    return ret;
};

Now we can join them together:

// Rounding function with algorithm specified
var _round = function(n, fd, alg) {
    fd >>>= 0;
    switch (alg) {
        case _ralgs.HALF_UP:
            return _round2PlusInfinity(n, fd);

        case _ralgs.AWAY_FROM_0:
            return _roundAwayFromZero(n, fd);

        default:
            return _roundTowardsEven(n, fd);
    }
};

There’s one last bit of boilerplate before implementing our public API. One thing I dislike about toFixed is that you get trailing zeroes in your output whether you want them or not. You asked for six decimal places in your output? Here you go! Our API will, by default, suppress useless zeroes but the caller can specify a minimum number as an optional argument. We need a function to make that possible:

// Applies minimum / maximum fractional digits
var _trimFraction = function(s, minFd, maxFd) {
    var splitPoint = s.indexOf('.'), i = s, j, f = "";
    if (splitPoint === -1 && minFd === 0) {
        return s;
    }
    if (null == minFd) {
        minFd = 0;
    }
    if (null == maxFd) {
        maxFd = 2;
    }
    if (splitPoint >= 0) {
        f = s.substring(splitPoint + 1, s.length);
        i = s.substring(0, splitPoint);
    }
    if (minFd) {
        // Add trailing zeroes
        for (j = f.length; j < minFd; j++) {
            f += '0';
        }
    }
    else {
        // Trim excess seroes
        f = f.substring(
            minFd, maxFd).replace(/0+$/, "");
    }
    if (f) {
        return i + '.' + f;
    }
    return i;
};

Our public API consists of some properties and a method added to Number.prototype:

// Algorithm specification
window.Rounding = {
    HALF_TO_PLUS_INFINITY : _ralgs.HALF_UP,
    HALF_AWAY_FROM_ZERO : _ralgs.AWAY_FROM_0,
    HALF_TO_EVEN : _ralgs.TO_EVEN,
    // Default rounding method is
    // ROUND_HALF_TO_EVEN
    algorithm : _ralgs.TO_EVEN
};

// Add a roundTo method to Number
var rt = function(maxFd, minFd) {
    if (!isFinite(this)) {
        return this + '';
    }
    // Require numbers >= 0
    maxFd = Number(maxFd);
    minFd = Number(minFd);
    if (!(isFinite(maxFd) && maxFd >= 0)) {
        maxFd = 0;
    }
    if (!(isFinite(minFd) && minFd >= 0)) {
        minFd = 0;
    }
    if (minFd > maxFd) {
        minFd = maxFd;
    }

    return _trimFraction(
        _round(this, maxFd, window.Rounding.algorithm), minFd, maxFd);
}, mName = "roundTo", obj = window.Number.prototype;
if (!(mName in obj)) {
    try {
        Object.defineProperty(obj, mName, {
             value : rt,
             enumerable : false
        });
    }
    catch(e) {
        // Do it the old fashioned way
        obj[mName] = rt;
    }
}

Because of the way we’ve implemented our rounding function, we don’t have to worry that someone might set Rounding.algorithm to “Dave”; this means that we don’t have to use a getter / setter for the property. Some Internet experts expend a lot of hot air on the evils of extending built-in types, but Number is absolutely the right place to add our method since we can now use it in place of toFixed and the ability to extend Objects is a central feature of JavaScript anyway. Do note, however, how we go about adding our method – this is the nice way to do it; stomping over someone else’s roundTo method is not polite!

Let’s try it out. Tell me, computer, what is the result of rounding 1.015 to two decimal places?

Hurrah! Remember that it’s generic enough to handle very small numbers? Tell me, computer, what is 1.25×10-26 to 27 decimal places?

Note, this is not wrong – it is the round half to even algorithm. If we set the algorithm to round half to plus infinity and ask again, we get a slightly different answer:

If you don’t want to use a different rounding function, there’s no reason why we can’t simply fix toFixed! Here’s a patch:

(function() {
    if ((0.1).toFixed(20) ===
        "0.10000000000000000000") {
        // Not broken
        return;
    }
    var m = function(fd) {
        return this.roundTo(fd, fd);
    }, obj = Number.prototype, mName = "toFixed";
    try {
        Object.defineProperty(obj, mName, {
            enumerable : false,
            value : m
        });
    }
    catch(e) {
        obj[mName] = m;
    }
})();

And the answer to the original question of how hard can it be? The answer is: harder than you think!

You can download the complete library or, if you prefer, a a minified version.