Search code examples
javascriptglobaldefault

Getting overwritten default browser object in Javascript


Is there a way to get the default value of an object in the global scope?

For example, let's say that I need to use Math.round, but Math.round has been overwritten with another value. Here's an example of what I'm talking about:

// script1.js (can't be edited)
Math.round = () => null;
Object.freeze(Math); // delete Math.round method and freeze Math object

// script2.js (loads after script1.js)
console.log(Math.round(3.141592)); // should return 3

Is it possible to get the default value that the browser sets (function round() { [native code] }) after it is overwritten in Javascript?


Solution

  • The only solution I can think of is to use iframes. Each iframe will have it's own newly-created window object, which you can then use in the parent frame (if they're of the same origin).

    Math.round = () => null
    const frame = document.createElement('iframe')
    document.body.appendChild(frame)
    
    Math.round(2.5) // null
    frame.contentWindow.Math.round(2.5) // 3
    

    You can even call DOM functions from the iframe against the current page if you supply the right "this" to the function:

    // will return your page's body, not the body in the iframe.
    // This is because we're telling it to use our document object as "this", instead of the iframe's document.
    frame.contentWindow.document.querySelector.call(document, 'body')
    

    In the future, we may get better support for being able to run scripts in their own isolated "realm", where they can have their own separate global enviornment to muck around with. See this upcoming ecmascript proposal to learn more. (at the time of writing, this is currently in stage 2)

    Finally, I'll note a couple alternative solutions that may be a better way to go depending on the situation:

    • If you have full control over the page, then you should be able to save off global variables before you load these naughty scripts. Alternatively, you could load the script in an iframe to isolate it's bad behavior.
    • If possible, it might be better just to let the globals get modified. Scripts really shouldn't be touching them, and if they are, it's probably because they're trying to pollyfill some missing features. Its rare that a script is actually making breaking changes to global function - but if they are, it might be worth it to file a bug report with the script author to fix this behavior.