Fail proof access to JavaScript’s built-in types…

on , most recently modified on

JavaScript is a beautiful programming language, the de facto client side scripting language of the web until something new comes along, which I don’t think will ever happen. It’s extremely elastic in that one can create user defined methods to use with built in objects like Functions, Arrays and even generic objects. It exposes DOM and HTML interfaces that one can extend as per the requirements of the web app they’re building.

It is so flexible that features not available in certain browsers, due to poor implementations of W3 standards or a complete disregard of their recommendations, could be added dynamically by writing JavaScript code that fills in those gaps, usually referred to as shims or polyfills. However, with this kind of malleability, it is also possible to overwrite built-in objects references.

Messing up built-in objects

Take for instance the following snippet.

String.prototype.reverse = function () {
    var out = [];
    for ( var i = this.length - 1; i >= 0; i-- ) {
        out.push( this.charAt( i ) );
    }
    return out.join( '' );
}

After writing that piece, I can very easily reverse a string just by using the ‘reverse’ method on a string primitive or a String object. This is because the built in object is available for access in the global namespace via ‘String‘. The problem is I can redefine String to anything I want.

String = 'LOL'

If I write this piece of code before I define the reverse method, a TypeError will be thrown because String is now simply a variable that happens to hold the string ‘LOL’ instead of a reference to the String object. It’s still there somewhere, mind you, but it cannot be accessed because the only link to it has been severed. In fact, I didn’t really need to overwrite the String variable. I could just as easily do the following.

delete window.String

That would basically delete the global variable String completely.

This is kind of a problem for those who build open source JavaScript libraries as it’s now at the mercy of the user. A script call to one that simply executes a rewrite or deletion of any or all those variables – Function, Number, String, Array, Object – prior to your script will ensure your work is rendered useless. Luckily for you, I exist.

Good?! So what to do?

Well, we’ll first need to understand that JavaScript lets data of certain types exist in two different forms – primitives and objects.

Primitives

The following snippet shows the initialisation of a variable into a string primitive.

var str = 'Hello'

Here, the variable str contains the string ‘Hello’. There is nothing more to the variable. No properties can be assigned to it if we tried.

str.xyz = 'World'

That snippet would fail to affect the variable str usually. In JavaScript strict mode, it will throw a TypeError as str is not an object, just a primitive. Primitives can be instantiated without any issues and regardless of the presence of the String function.

Objects

The line below will create an object of the String function and save a reference to it in the variable str.

var str = new String( 'Hello' )

This str can now be assigned properties. Here’s something else: the constructor property of str holds a reference to the String function.

var strCons = str.constructor // strCons now references the String function

But how is that relevant?

Yeah! What does that matter? If the String function itself gets messed up, how are you going to initialise a String object in the first place, let alone access its constructor?

Well, JavaScript does this thing called type coercion. It’s what makes it such a fun language to code in.

Type coercion

The constructor property and basically every property and method that forms the prototype of the String function can also be accessed on primitives. JavaScript will coerce the string primitive to act like a String object for commands where it is necessary.

This means, writing a snippet like so…

var Str = 'hello'.constructor

… would let Str be the new reference to the built-in String function.

Nice! Does it work on other types?

Sure it does. The following is how one can access the other built in constructors.

var Num = (0).constructor // Number
var Bool = (false).constructor // Boolean
var Arr = [].constructor // Array
var Fn = (function () {}).constructor // Function
var Obj = ({}).constructor // Object

Optimisations

JavaScript objects are also associative arrays, which is why instead of accessing the constructor property of the different coerced primitives, we could access the value of the ‘constructor’ key. So, to access Number, we could write something like…

var Num = (0)['constructor']

Now, since the string 'constructor' can be stored in a variable, we can access all constructors of all the built in types as follows.

There’s a reason we don’t assign values to a variable called constructor in the global scope.

var constr = 'constructor'

var Str = ''[constr]
var Num = (0)[constr]
var Bool = (false)[constr]
var Arr = [][constr]
var Fn = (function () {})[constr]
var Obj = ({})[constr]

Of course, we don’t need to use the empty string there. constr already exists. We can just use that instead. Also, we don’t need the empty anonymous function literal. The constructor of String, Number and every built in type is a Function.

var Str = constr[constr]
var Fn = constr[constr][constr]

Let’s store our new references to these types with their proper names as properties of a globally accessible object.

(function () {

    var constructor = 'constructor'

    window.Types = {
        String : constructor[constructor],
        Number : (0)[constructor],
        Boolean : (false)[constructor],
        Array : [][constructor],
        Function : constructor[constructor][constructor],
        Object : ({})[constructor]
    }

})()

This can, of course, be further optimised to…

(function () {

    var c = 'constructor'

    window.Types = {
        String : c[c],
        Number : 0[c],
        Boolean : (!1)[c],
        Array : [][c],
        Function : c[c][c],
        Object : {}[c]
    }

})()

And there you have it.

Thanks for reading. I hope you’ve found this helpful. Can this piece be extended? Did I miss anything? Do you wish to know more? Critiques? Let me know in the comments…