views:

238

answers:

4

I'm creating my own JavaScript Array-like object and I have methods that call closures. I was just wondering where was the most efficient place to define a closure.

For example, imagine I have a map function and a chop function:

MyObject.prototype = 
{
  map: function(fn) { ... applies fn to each element ... };

  chop: function() 
  { this.map( 
    function(element) 
    {
      ... chop off last character ... 
    } 
  )};
}

Is it more efficient to do this instead?

MyObject.prototype = 
{
  map: function(fn) { ... applies fn to each element ... };

  __chop: function(element) 
  {
    ... chop off last character ... 
  }

  chop: function() 
  { this.map(this.__chop) };
}
A: 

They are effectively the same thing - go with whichever one is more readable. For what its worth I prefer the second one.

Andrew Hare
So there's no difference in terms of how the interpreter deals with those cases?
cdmckay
Not really - Allain explains it pretty well in his answer.
Andrew Hare
-1: see my answer
Christoph
+2  A: 

Neither creating the function, nor looking it up are costly operations in JavaScript, so if you have an "array" with a decent # of elements in it, the difference between either method will be negligible.

Allain Lalonde
+1 better explanation :)
Andrew Hare
-1: the overhead of function creation may be small, but you'll get it an **each call** to `chop()`
Christoph
agreed, still negligible.
Allain Lalonde
Yeah but I was looking more for something like Christoph was saying... I know they are negligible but I'm still curious which one is more efficient, however slightly.
cdmckay
@Allain: you can only know if something is negligible or not **after** benchmarking your application; might be `chop()` will be called millions of times, meaning millions of unnecesarry function objects have to be created (and garbage collected)
Christoph
It's not a blanket statement. As the number of elements grows, the relative cost of creating the function vs invoking the function will become less. Of course I agree with you, you should always benchmark for the particular environment your code will be running in.
Allain Lalonde
@Allain: The overhead might be O(1) in the number of elements for each call, but it's still O(n) in the number of calls; if you only call `chop()` a few times, the overhead will be negligible; but when you have a lot of calls to `chop()`, the impact might well be relevant...
Christoph
+2  A: 

The second one is more efficient. This

  chop: function() 
  { map( 
    function(element) 
    {
      ... chop off last character ... 
    } 
  )}

will create a new function object on each call to chop() with the respective runtime and memory overhead. As there won't be any lingering references to the new object, it can be immediately gargage collected, but it's still bad practice to create more objects than necessary.

I'd suggest the following pattern:

MyObject.prototype = (function() {

    function map(fn) { ... }

    function chopElement(element) { ... }

    function chop() {
     this.map(chopElement);
    }

    return {
     map : map,
     chop : chop
    };

})();
Christoph
I like this approach since it doesn't pollute the "array"'s public interface and it still breaks chopElement out.
Allain Lalonde
A: 

Trading a function closure, for another function closure doesn't lead to a more efficient code. The most memory efficient one would be one that does not use closures at all.

__proto__ = {
  map: function(){},
  _chop: function(str){
    return str.slice( str.length, -1 );
  },
  chop: function(arr){ 
    this.map(this._chop, arr);
  }
}

This question rates very high on google for "closure memory usage", I don't think it qualifies. This is a problem that is difficult to diagnose though.

The answer here is more an example of hiding functionality within a closure, but it adds the cost of maintaining that memory space to store those private variables.

Drew