9

I'm using jQuery and have a function wrapped inside an immediately-invoked function expression like so:

<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
    (function ($) {

        var message = 'x called';

        function x() {
            alert(message);
        }
    })(jQuery);

    x();
</script>

This will result is an error since the function "x" is not defined outside the immediately-invoked function expression. Is there any way to call the function "x" outside the immediately-invoked function expression?

Halcyon
  • 14,631
  • 17
  • 68
  • 99
  • No, however it is possible to define a global variable named `x` that contains the function – Kevin B Jan 09 '13 at 20:20
  • 7
    Sure, but why would you mess with the scoping like this? The whole point of the immediate-invocation syntax is to prevent polluting larger scopes. – Matt Ball Jan 09 '13 at 20:21
  • 1
    [this](http://stackoverflow.com/questions/598878/how-can-i-access-local-scope-dynamically-in-javascript) might be of interest to you. – Christian Jan 09 '13 at 20:21
  • Just to chime in here. I totally agree with @MattBall. You can expose a `Namespace` as suggested below to have access to your methods and properties. It would have been beneficial if elaborated on what you are trying to do, ie: are you calling `x()` from an event? – pixel 67 Apr 30 '16 at 13:29

8 Answers8

9

Only if you expose the function in some way. For example, you can return it from the outer function:

var x = (function ($) {

    var message = 'x called';

    function x() {
        alert(message);
    }

    return x;
})(jQuery);

x();

Or, similarly, you can return it on an object:

var obj = (function ($) {

    var message = 'x called';

    function x() {
        alert(message);
    }

    return {"x": x};
})(jQuery);

obj.x();

Functions and variables declared inside of a function are not directly reachable from outside of that function, unless you provide some means of accessing them by returning something, or giving a reference to a variable declared outside of that function.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
5

Make a namespace for other classes or functions you might want to do this with. You don't want to continually pollute the global namespace but there's no reason you can't make one namespace that's global and put your individual things underneath that:

(function($){
  window.MyNamespace = function(){};
  var message = "Something here";

  $.extend(MyNamespace, {
    x: function(){
      alert(message);
    }
  });
})(jQuery)

MyNamespace.x()
nzifnab
  • 15,876
  • 3
  • 50
  • 65
2

You can change your code as follows:

<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript">
    var x;
    (function ($) {

        var message = 'x called';

        x = function () {
            alert(message);
        }
    })(jQuery);

    x();
</script>

jsFiddle link for this: http://jsfiddle.net/aLnbn/

malkassem
  • 1,937
  • 1
  • 20
  • 39
1

Yes, ( one way is to: )just return it from the IIFE using a return statement, also you need to "catch" the return by assigning a variable to the IIFE

var foo = (function(){

    return your_function;

}());
1

You can access your method by using your IIFE to return (or augment) a global variable.

You might do it like this:

var globalObject = (function (theObject, $) {

        if (theObject.theMethod) {
            return theObject;
        }

        var message = 'theMethod called';

        theObject.theMethod = function () {
            alert(message);
        };

        return theObject;

})(globalObject || {}, jQuery);


globalObject.theMethod();

The pattern we use is slightly better.

We have one global object (ie namespace) and we add modules to it by importing js files that contain IIFE's.

Each IIFE adds a new module to a single global object.

This makes it so our entire project has only one global object that can optionally utilize any of our modules by including a file.

I recommend checking out this article, which is a good discussion on the JavaScript module pattern:

jahroy
  • 22,322
  • 9
  • 59
  • 108
0

Try this:

var miFunc = (function($) {
    var message = 'x called';
    function x() {
        console.log(message);
    }
    this.x = x;
    return this;
})(jQuery);
miFunc.x();

Test: http://jsbin.com/erucix/2/edit

karacas
  • 2,054
  • 1
  • 19
  • 29
0

One of the purposes of a closure is to limit scope. That is why x() is defined and can be called inside of your immediately-invoked function expression but is undefined outside.

To have your code work without refactoring, you can take advantage of JS grammar which differentiates between a function statement and a function operator. Both are semantically identical but the latter can be assigned to a variable which works just right for your scenario:

var x; //scoped *outside* of the closure
(function ($) {
  var message = 'x called';
  x = function() {
    alert(message);
  }
})(jQuery);
x(); //alerts 'x called'
Oleg
  • 24,465
  • 8
  • 61
  • 91
0

You can access your method by using your IIFE to return a global variable.

//IIFEs - Immediately Invoked Function Expressions
var namespaceTestIIFE = (function ($) {

    /** Public functions and state. */
    var pub = {};

    $(document).ready(function () {
        //your on ready logic
    });

    pub.testAlert = function () {
       alert('Hello TestAlert');
    }
    return pub;
})(jQuery);

OR

var compareForm = (function ()
{
        /** Public functions and state. */
        var pub = {};
        pub.testAlert = function () {
           alert('Hello TestAlert');
        }
    return pub;
}());

To access function use "namespace.functionname" for example -

namespaceTestIIFE.testAlert();
Ravindra Vairagi
  • 1,055
  • 15
  • 22