7

Studying one JavaScript library I found following construction:

theMethod: function () {
    var m1 = new SomeClass();
    return function (theParameter) {
        this.someMethod();
        m1.methodCall(this.someField1);
        this.someField2 = 'some value';
    }
}()

theMethod is called as follows:

c.theMethod(paramValue);

What did the author want to say with this declaration?

Why not to use such declaration:

theMethod: function (theParameter) {
    var m1 = new SomeClass();
    this.someMethod();
    m1.methodCall(this.someField1);
    this.someField2 = 'some value';
}
Paul
  • 25,812
  • 38
  • 124
  • 247
  • 1
    @dystroy: I am sure. Look at the brackets at the end of `theMethod` declaration. – Paul Jun 21 '13 at 12:31
  • 1
    _"Why not to use such declaration?"_ Because the two are not equivalent. It's the same difference between a piece of data, and a function which returns a piece of data. – Matt Ball Jun 21 '13 at 12:31
  • Can you share the actual code? – Patrick McElhaney Jun 21 '13 at 12:31
  • 6
    There are many reasons for closure based function factories but it's hard to tell here why it's being used, the code is too abstracted. – Denys Séguret Jun 21 '13 at 12:32
  • @Patrick McElhaney: sure, it is a three.js library. Method is named THREE.Object3D.applyMatrix – Paul Jun 21 '13 at 12:33
  • This? https://github.com/mrdoob/three.js/blob/b376885578984fa0e1fb4f5ec7b43da07ff050be/src/core/Object3D.js#L53 – Patrick McElhaney Jun 21 '13 at 12:36
  • @Patrick McElhaney: yes, you have pointed the right place out. – Paul Jun 21 '13 at 12:37
  • 1
    @Paul Juhana answer explain the what is it doing question, but see my answer as for the why. – Hoffmann Jun 21 '13 at 13:01
  • 3
    One thing that helps with code like this is to put a set of parentheses around the outer function: `(function () { ... })()`. This is a convention that helps to flag up to anyone reading the code that you're going to immediately call the function with that second set of empty parentheses `()`. Otherwise when someone reads `theMethod: function () { ...` they're likely to assume that the function they're now reading is going to be the thing that runs when `theMethod` is called. – Daniel Earwicker Jun 21 '13 at 14:34
  • @DanielEarwicker, well put. Years ago, I didn't think the outer brackets mattered but was eventually convinced by this precise point of view. – Beetroot-Beetroot Jun 21 '13 at 18:03

4 Answers4

5

Declaring the variable outside the function makes the function use the same object every time.

An example (with an integer instead of an object, for simplicity's sake):

var c = { 
    theMethod: function () {
        var m1 = 0;
        return function (theParameter) {
            m1++;
            console.log( m1 );
        }
    }()
};

c.theMethod(); c.theMethod();  // output: 1 2


var d = { 
    theMethod: function () {
        return function (theParameter) {
            var m1 = 0;
            m1++;
            console.log( m1 );
        }
    }()
};

d.theMethod(); d.theMethod();  // output: 1 1

The self-invoking function works like this:

var c = { 
    theMethod: function () {
        var m1 = 0;
        return function (theParameter) {
            m1++;
            console.log( m1 );
        }
    }()
};

When the object c is created, the self-invoking function invokes itself and theMethod now equals the return value of that function. In this case the return value is another function.

c.theMethod = function( theParameter ) {
    m1++;
    console.log( m1 );
};

The variable m1 is available to the function because it was in scope when the function was defined.

From now on when you call c.theMethod() you are always executing the inner function that was returned from the self-invoking function, which itself executed only once at the time the object was declared.

The self-invoking function works just like any function. Consider:

var c = { 
    theMethod: parseInt( someVariable, 10 )
};

You don't expect parseInt() to execute every time you use the c.theMethod variable. Replace parseInt with an anonymous function as in the original and it's exactly the same thing.

JJJ
  • 32,902
  • 20
  • 89
  • 102
3

It's for encapsulation. m1 is hidden to other methods and from external access by places that might use theMethod. Javascript programmers usually don't care about encapsulation (but they should on non-trivial scripts) because you need to use closures which complicates design of classes and when implemented poorly can reduce performance. That is why you don't see this kind of structure often outside of libraries.

Also your second piece of code is not equivalent. Something equivalent would be:

theMethod: function (theParameter) {
    if (typeof this.prototype.__private__ === "undefined") {
        this.prototype.__private__= {}
    }
    if (typeof this.__private__.m1 === "undefined") {
        this.prototype.__private__.m1= new SomeClass();
    }
    this.someMethod();
    this.__private__.m1.methodCall(this.someField1);
    this.someField2 = 'some value';
}

But then m1 is not really private here.

Also note that in that piece of code m1 is only visible to the function returned, if theMethod was a member of a class the other methods of that class would not be able to see m1 (making it different than the "private" keyword on Java). Also depending on how you declared theMethod m1 would be the java equivalent to "static" (m1 is a function on the prototype of an object it's static, if it's not on a prototype it's not static).

Hoffmann
  • 14,369
  • 16
  • 76
  • 91
  • perfect explanation! And, of course, Juhana should be thanked too. – Paul Jun 21 '13 at 13:10
  • I understood! Let me complement your answer. How this works: the line `theMethod: function` does not declare a `function()` named `theMethod` but instead an anonymous `function()` is called once(!!!), when JavaScript interpreter constructs the object, and result of this call is passed to `theMethod` field. This result is a closure using a pre-initialized `m1` variable. – Paul Jun 21 '13 at 13:26
  • Notice that using the `this` keyword here might not be the best example, since the function in question is a prototype method actually and invoked on different instances. It had to be `….prototype.__private__ = {};` therefore. – Bergi Jun 21 '13 at 13:49
  • @Paul you are correct and also Bergi is right, my code snippet only makes sense if theMethod was a method of a prototype (I'm very careful when using the term "class" in javascript since Javascript does not have classes). I will correct the answer – Hoffmann Jun 21 '13 at 14:01
  • Who said "Javascript programmers usually don't care much about encapsulation" and that " you don't see this kind of structure often"? Javascript programmers actually care very much and tend to use encapsulation rather a lot. For example, just about every mainstream jQuery plugin is encapsulated, as are all modules of the Module Pattern. The importance of encapsulation to tidy javascript cannot be overstated. – Beetroot-Beetroot Jun 21 '13 at 16:51
  • 1
    @Beetroot-Beetroot you are right, there are several design patterns for encapsulating plugins and such. When you are making a plugin that is going to be used by other people you do care a lot about encapsulation. But in simple scripts that are only going to run on my own pages I usually don't try to encapsulate if it's going to generate a more hard to read code. Regardless I will rectify my answer as it may suggest that encapsulation is not important in Javascript. – Hoffmann Jun 21 '13 at 16:52
  • @Beetroot-Beetroot To be fair, it probably depends on one's background. (Seeing as many people still program JS as part of an application written in something else.) So a Python person likely wouldn't care about data encapsulation at all, but try and keep module namespaces uncluttered. – millimoose Jun 21 '13 at 17:29
  • Hoffman, you take criticism on the chin like a gentleman sir! – Beetroot-Beetroot Jun 21 '13 at 17:47
  • @Beetroot-Beetroot english is my second language so I tend to be a little too formal when writing in it, but thank you =) – Hoffmann Jun 21 '13 at 18:39
  • I have family in Brazil ... stay safe. – Beetroot-Beetroot Jun 21 '13 at 20:19
1

@Juhana is right. Here's a handy tutorial on how closures work. http://www.javascriptkit.com/javatutors/closures.shtml

Paul
  • 85
  • 6
1

What did the author want to say with this declaration?

That the m1 value should be reused for every call. In your closure-less alternative, it would instantiate a new SomeClass object with every call. It either is used simply for performance improvement, or (and) to maintain a common state in the m1 object.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • That's my point. I do not understand the use of closure when an outer object is re-created with every call. – Paul Jun 21 '13 at 12:42
  • 1
    But with the closure it is not recreated? Or what do you mean by "outer" object? – Bergi Jun 21 '13 at 12:45