1

Is there any way I can override a closure so it does part of what the original closure does? I know there's no straightforward way, but is there some hack? I'm willing to be messy...

<html>
    <head>

        // I DON'T CONTROL THIS CODE!!!
        <script>
        ;(function() {

            function _dothing() {
                alert("_dothing");
            }

            function _doit() {
                _dothing();
                alert("_doit");
            }

            window.K = { doit : _doit };

        })();
        </script>
    </head>
<body>

    // I DO CONTROL THIS CODE
    <script>

        function mydoit() {
            alert("mydoit");
            _dothing();         <-- THIS FAILS, IS THERE ANY WAY TO SUCCEED? :(
        }

        window.K.doit = mydoit;
        window.K.doit();
    </script>

</body>
</html>
Colin
  • 3,670
  • 1
  • 25
  • 36

4 Answers4

1

I think you can use jQuery to get the content of the script tag and after that you can use eval see this question.

Community
  • 1
  • 1
dignifiedquire
  • 1,360
  • 9
  • 14
1

When you put code inside this:

(function() {

})();

it's called a self invoking function, and creates a scope that you can't access (just like not being able to access a function's scope anywhere else...only inside of it) - it is run as soon as it is declared. The fact that you can call window.K.doit is because the code extends the global window object. Since you have access to window everywhere, it can be called, but only with window.K.doit or K.doit. This is how jQuery plugins are normally defined - they extend the global jQuery object without exposing any of their code directly. Sooooo no, you are not able to access it unless you do something like what the other answerer proposes - but be careful with using eval, as TECHNICALLY, any script could be inserted and you could "assume" it's right/trusted and eval it.

Ian
  • 50,146
  • 13
  • 101
  • 111
  • Doh. Unfortunately I don't think I can even do the eval trick. The first block of code (the one I don't control) actually is 'injected' into a UIWebView on iOS using stringByEvaluatingJavascriptFromString. So I don't even know where that context would be. I guess I'm hosed :( – Colin Oct 18 '12 at 18:27
  • But can't you wait until it's injected and read in the javascript? Or is it already evaluated when it's injected? – dignifiedquire Oct 18 '12 at 19:03
1

You can try something like this (I know this is very nasty, but, as others pointed out, it seems to be the only way):

function mydoit() {
    alert("mydoit");
    _dothing();
}

var f = new Function(document.scripts[0].text.replace(/(}\)\(\);\s*)$/, "window._dothing = _dothing;\n$1"));
f();
window.K.doit = mydoit;
window.K.doit();

Tested on Firefox, Chrome and IE8.

Beware: this is creating a hole new context, it's not the same as the already created. It is calling just a copy of _dothing, not the original.

Pato
  • 671
  • 6
  • 17
  • Massively hacky, and it just might work! Testing now with our (a bit more complicated) actual use case... – Colin Oct 18 '12 at 21:58
-1

You have to create a global variable from within the anonymous / self executing function: this tutorial will show you how: http://professionalaspnet.com/archive/2012/07/29/Make-Your-JavaScript-Better-With-Self-Executing-Anonymous-Functions.aspx

Jeff Wooden
  • 5,339
  • 2
  • 19
  • 24