5

Reading some legacy code, and found

A.prototype.setSize: function () {
   var v1 = new Vector2();
   return function (size ) {

     var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
     this.min.sub( halfSize );
     return this;

   };

}(),

I am wondering:

  1. why define setSize as a function which return another function
  2. Also the defined function is executed right away.

any light to shed on this?

Updated:

I can simply use

   A.prototype.setSize: function (size) {
       var v1 = new Vector2();

       var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
       this.min.sub( halfSize );
       return this;

    },

Is the first snippet better than second?

Adam Lee
  • 24,710
  • 51
  • 156
  • 236
  • If you need to optimise `setSize` then the first closure version is probably better. I find it less readable though, so if if performance isn't necessary I'd just use your second flatter version. – Kit Sunde Aug 12 '15 at 00:23

4 Answers4

5
  1. So the returned function can access the value of v1 each time it is called without making v1 a global (or otherwise non-private)
  2. That is so the returned function is assigned to setSize
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 1
    I don't need to set v1 as global, I can just use var v1? – Adam Lee Aug 11 '15 at 23:56
  • @AdamLee — You have to put the `var` statement *somewhere*. There isn't anywhere other then the closure to put it that either (a) Wouldn't make it available to other code or (b) Would recreate it each time `setSize` was called. – Quentin Aug 12 '15 at 06:55
2

The purpose in that particular case is to avoid creating a new Vector object each time setSize is called. It's a caching strategy. The alternative would be to just have a flat function:

A.prototype.setSize: function (size) {
  var v1 = new Vector2();
  var halfSize = v1.copy(size).multiplyScalar(0.5);
  this.min.sub(halfSize);
  return this;
}

I would only use the closure cached version of setSize if I found I was having performance problems because of new Vector2().

Kit Sunde
  • 35,972
  • 25
  • 125
  • 179
2

A classic example is:

function createAdder(x) {
  return function add(y) {
    return x + y;
  }
}

var addTwo = createAdder(2);
// addTwo is a function that takes one input and adds 2 to it
addTwo(3); // 5
addTwo(9); // 11

The idea is that you want to create a function, but the function you want to create depends on something. In this case, we wanted to create an addX function.

See Chapter 5 of Eloquent Javascript for more. Particularly the Higher Order Functions section.


It also can be more DRY. Consider:

function createSecretAdder() {
  var secretNumber = generateSecretNumber(); // THIS TAKES A LONG TIME
  return function(n) {
    return secretNumber + n;
  }
}
var secretAdder = createSecretAdder(); // slow
secretAdder(2); // fast
secretAdder(7); // fast

vs.

function createSecretAdder() {
  return function(n) {
    var secret = getSecretNumber(); // THIS TAKES A LONG TIME
    return secretNumber + n;
  }
}
var secretAdder = createSecretAdder(); // fast
secretAdder(2); // slow
secretAdder(7); // slow

The former is DRYer and faster than the latter. This should address your comment and the update to your question.

Note: you'll have to understand closures to understand how this stuff works.


As for why it's immediately invoked, see here.

Community
  • 1
  • 1
Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
2

It function closure. Used to hide variables from global scope. Read on and see some examples here

JS function closures

Maksym Kozlenko
  • 10,273
  • 2
  • 66
  • 55