How to do a browser check for a function
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.
Download the sample JS file at the end of the page to try it for yourself if you like.
This one fails on some browser
This one is better
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:
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.
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
Look at the following JavaScript samples. One of them works reliably across browsers, the other one doesn't.
Download the sample JS file at the end of the page to try it for yourself if you like.
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:
- Just the browser check, no overriding
- Browser check, then override (faulty)
- Browser check, then override (correct)
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