0

In JavaScript, is it possible to move inner functions from one function into the global scope? I haven't yet found any straightforward way to do this.

function moveMethodsIntoGlobalScope(functionName){
    //move all of functionName's methods into the global scope
    //methodsToPutIntoGlobalScope should be used as the input for this function.
}

//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope(){
    function alertSomething(){
        alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
    }
    function alertSomethingElse(){
        alert("This should also be moved into the global scope.");
    }
}
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • This is not possible this way, you can make `methodsToPutInGlobalScope` an object instead of function and then you will be able to access functions inside it. – Dfr Apr 24 '13 at 17:21
  • Does `methodsToPutInGlobalScope` only have function declarations inside it, or is there more? For example, using eval *could* work, but might not be what you want if there are more than function declarations inside the function. – Paul Grime Apr 24 '13 at 17:25

3 Answers3

2

If you don't want to make changes in methodsToPutInGLobalSpace you can use the following dirty hack:

var parts = methodsToPutInGlobalScope.toString().split('\n');
eval(parts.splice(1, parts.length - 2).join(''));

As final solution we can use:

moveMethodsIntoGlobalScope(methodsToPutInGlobalScope);
alertSomething(); //why doesn't this work?

function moveMethodsIntoGlobalScope(functionName){
    var parts = functionName.toString().split('\n');
    eval.call(window, parts.splice(1, parts.length - 2).join(''));  
}

//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope(){
    function alertSomething(){
        alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
    }
    function alertSomethingElse(){
        alert("This should also be moved into the global scope.");
    }
}

Live demo

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
Minko Gechev
  • 25,304
  • 9
  • 61
  • 68
  • This answer still doesn't explain how to implement `moveMethodsIntoGlobalScope`, which is what I was trying to do in the first place. – Anderson Green Apr 24 '13 at 17:17
  • There's no trivial way to do this. I guess you need to parse `moveMethodsIntoGlobalScope` (use `moveMethodsIntoGlobalScope.toString()` to get the string representation) and after that declare the inner functions in the global scope. – Minko Gechev Apr 24 '13 at 17:19
  • Done! You can see the changes. – Minko Gechev Apr 24 '13 at 17:23
  • Have you tested this solution yet? I couldn't get it to work: http://jsfiddle.net/5CC52/1/ It produces this error in the console: `Uncaught ReferenceError: alertSomething is not defined` – Anderson Green Apr 24 '13 at 17:27
  • I like it, but there are some `Function.prototype.toString` gotchas to be wary of - http://stackoverflow.com/a/3379880/319878. – Paul Grime Apr 24 '13 at 18:00
  • I've noticed that pre-existing functions aren't being replaced in the global scope. Is there any way to work around this problem? http://jsfiddle.net/5CC52/5/ – Anderson Green Apr 24 '13 at 19:36
  • Actually they are replaced but in jsfiddle everything is wrapped inside a function look at this: http://jsfiddle.net/mgechev/5CC52/6/ – Minko Gechev Apr 24 '13 at 19:40
  • @MinkoGechev Hm. Would it be possible to replace each original function inside `moveMethodsIntoGlobalScope`? – Anderson Green Apr 24 '13 at 19:51
  • What do you mean with that? Each function declared in `moveMethodsIntoGlobalScope` is being defined as global and replaces any other function with the same name. The issue in JSFiddle was not because of the solution but because `alertSomething` (not the one declared at `moveMethodsIntoGlobalScope`) was declared in the local scope of the `onload` function. – Minko Gechev Apr 24 '13 at 20:04
1

Not very sophisticated, but would work.

function copyInto(arr, context) {
    //move all of functionName's methods into the global scope
    //methodsToPutIntoGlobalScope should be used as the input for this function.
    for (var i = 0; i < arr.length; i += 2) {
        var exportName = arr[i];
        var value = arr[i + 1];
        eval(exportName + "=" + value.toString());
    }
}

//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope() {
    function alertSomething() {
        alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
    }

    function alertSomethingElse() {
        alert("This should also be moved into the global scope.");
    }

    copyInto(["alertSomething", alertSomething, "alertSomethingElse", alertSomethingElse], window);
}

methodsToPutInGlobalScope();
alertSomething();
alertSomethingElse();
Paul Grime
  • 14,970
  • 4
  • 36
  • 58
  • When `methodsToPutIntoGlobalScope` is called, it appears that it doesn't overwrite pre-existing functions. Is there any way to work around this problem? http://jsfiddle.net/5CC52/9/ – Anderson Green Apr 24 '13 at 19:41
  • Strange. This will work `window["alertSomething"]();`. Looks like the method call is bound to the original, but an indirect method call will work. – Paul Grime Apr 24 '13 at 19:52
  • It works with `eval`, like the answer from @Minko Gechev - http://jsfiddle.net/fiddlegrimbo/5CC52/12/ – Paul Grime Apr 24 '13 at 20:12
0

Yes, this is possible. If you declare a variable using var keyword that variable becomes local only, but if you don't it becomes a global one.

function foo(){

   var test = 'test'; // <- Using var keyword
}

foo(); // <- execute the function

console.log(test); // undefined

But if we do the same thing without var keyword:

function foo(){

   test = 'test'; // <- Using var keyword
}

foo(); // <- execute the function

console.log(test); // test

In order to make your inner functions global, you'd declare anonymous functions without var keyword

function methodsToPutInGlobalScope() {

    alertSomething = function () {
        alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
    }

    alertSomethingElse = function () {
        alert("This should also be moved into the global scope.");
    }

}


methodsToPutInGlobalScope(); // <- Don't forget to execute this function


alertSomething(); // Works
alertSomethingElse(); // Works as well
Yang
  • 8,580
  • 8
  • 33
  • 58