Rik's Ramblings

Wednesday, July 29, 2015

Checking for a function in a browser

Fuck me! I just lost days of my life due to someone elses shitty code!

Look at the following JavaScript samples. One of them works reliably across browsers, the other one doesn't.

You can download the sample JS file and try it at home if you like, it gives you three different incarnations.


This one fails on some browser
if ("undefined" === typeof(atob)){
   console.log("atob is not defined in this hacky case...");
    var atob = function(){
      console.log("Do something buggy");
    }
}
else {
   console.log("atob is defined in this browser.");
}

This one is better
if ("undefined" === typeof (window.atob)){
   console.log("window.atob is not defined");
   window.atob = function(){
      console.log("do something buggy");
   }
}
else {
   console.log("atob is defined on the window object");
}

Hoisting


Basically what goes wrong in the first fragment, if I'm not mistaken, is that the variable declared in the if clause (var atob) gets hoisted. Think of it this way:

In JavaScript, any variable you declare in a scope is effectively declared on the first line of the file. So that first fragment is actually identical to this:

var atob;

if ("undefined" === typeof(atob)){
   console.log("atob is not defined in this hacky case...");
    atob = function(){
      console.log("Do something buggy");
    }
}
else {
   console.log("atob is defined in this browser.");
}

Of course, this means that the check 'typeof(atob)' is always going to return undefined. What the author was expecting, was that the check would find the atob on the global scope and only if it didn't exist declare a local variable in the if clause.

Sample

In the following sample there are three fragments to compare. You need to uncomment the one you want to test. Due to the nature of the buggy code, the three pieces of code cannot all be present at the same time.

Download a JavaScript file to play with