0

I got so confused here. Can someone help me peel the layers off the function definition here? What are the out-most parentheses for? Why argument (p) can be after }, and which function is it for? Where is q required at all? Why can p directly call publish() later?

var p = {};
(function(q) {
    q.publish = function(topic, data){
    ...
    };
}(p));
...
p.publish("inbox", "hello");
etlolap
  • 531
  • 1
  • 6
  • 14

3 Answers3

1

It simply creates the function and executes it immediately.

For example:

var foo = function() {
   return 5;
}();

console.log(foo);

will print 5.

If you want to learn more about it, please read this excellent article http://benalman.com/news/2010/11/immediately-invoked-function-expression/

I would like to quote module pattern example from the link I shared.

var counter = (function(){
    var i = 0;
    return {
        get: function(){
            return i;
        },

        set: function( val ){
            i = val;
        },

        increment: function() {
            return ++i;
        }
    };
}());

console.log(counter.get());
counter.set(3);
console.log(counter.increment());
console.log(counter.i);

Output

0
4
undefined

Here we are dynamically creating an Object at the same time we are making i private. This is called closure property.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
0

It's a self executing function. Using q is useless here since q === p.

var p = 'hello';
function f(q){ return q; }; f(p);    // "hello"
(function(q){ return q; }(p));       // "hello"
(function(){ return p; }());         // "hello"
/*(*/function(){ return p; }()/*)*/; // SyntaxError: Unexpected token (

This pattern is usually used to create a private context for variables. Here is a well known example :

var counter = function(){
    var i = 0;
    return function(){
        return ++i;
    };
}();

counter(); // 1
counter(); // 2
i; // undefined

Have a look at this great article : http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html.

0

Putting the function in parentheses means the JS interpreter takes it as a function expression, so it can be anonymous (i.e., not have a declared name). Adding () at the end means the function is called immediately. So, e.g.:

(function() {
   alert('Hi');
}());

...declares a really simple function with no arguments, and calls it immediately. A slightly more complicated one with an argument might look like this:

(function(someArgument) {
    alert(someArgument);
}('Hi'));

That would alert 'Hi', because the string 'Hi' is passed to the anonymous function when it is called.

So with that as background, here's what your code is doing line by line:

var p = {};      // declare variable p, referencing an empty object
(function(q) {   // make an anonymous function expression that takes one argument, q
    q.publish = function(topic, data){    // add a property 'publish' to whatever q is,
    ...                                   // where 'publish' is a function that takes
    };                                    // two arguments
}(p));     // call the anonymous function, passing p in
...
p.publish("inbox", "hello");    // call the method 'publish' that was added to p

The q argument that you asked about takes the value from p, so it refers to the same empty object, but then it adds the .publish() method to that object.

This general concept is called an "Immediated invoked function expression", or IIFE.

Usually if an IIFE is just sitting there by itself like that (i.e., another variable is not assigned equal to it) it is done so that working variables/functions can be created temporarily without adding them to the global scope, because in JavaScript the scope options are basically global or function. The code you show doesn't do that, but here's a simple example:

(function() {
    var x = 0;
    for (var i = 0; i < 100; i++)
       x += i;
    alert (x);
}());
// here x and i are not accessible because they're local to the function above.
nnnnnn
  • 147,572
  • 30
  • 200
  • 241