2

I was reading the source code for pallet.js and came across this.

var ret = (function(proto) {
  return {
    slice: function(arr, opt_begin, opt_end) {
      return proto.slice.apply(arr, proto.slice.call(arguments, 1));
    },
    extend: function(arr, arr2) {
      proto.push.apply(arr, arr2);
    }
  };
})(Array.prototype);
var slice = ret.slice;
var extend = ret.extend;

Why is this necessary? Why could they not simply write this:

var slice = function(arr,opt_begin,opt_end) {
  return Array.prototype.slice.apply(arr,[opt_begin,opt_end]));
}
var extend = function(arr,arr2) {
  return Array.prototype.push.apply(arr,arr2);
}

EDIT 1:

In response to the duplicate question. I don't think it is a duplicate, but that question definitely does address my question. So it is an optimization. But won't each one only be evaluated once? So is there really a significant improvement here for two function calls?

Also if we are worried about performance why are we calling proto.slice.call(arguments,1) instead of constructing the array of two elements by hand [opt_begin,opt_end], is slice faster?

retrohacker
  • 3,194
  • 4
  • 21
  • 31
  • 1
    possible duplicate of [Is a closure for dereferencing variables useful?](http://stackoverflow.com/questions/8288664/is-a-closure-for-dereferencing-variables-useful) – Bergi Mar 30 '14 at 18:05

2 Answers2

3

Because the syntax is just so much cooler. Plus you can rationalize it's use by telling yourself that it's more DRY. You didn't have to type Array.prototype twice.

sabof
  • 8,062
  • 4
  • 28
  • 52
0

I can't be sure what was the original rationale behind that code (only the author knows) but I can see a few differences:

  • proto is a closed-over local variable, while instead Array is a global. It's possible for a smart enough Javascript engine to optimize access because proto is never changed and thus it could even be captured by value, not reference. proto.slice can be faster than Array.prototype.slice because one lookup less is needed.

  • passing opt_begin and opt_end as undefined is not the same as not passing them in general. The called function can know if a parameter was passed and happens to be undefined or if instead it wasn't passed. Using proto.slice.call(arguments, 1) ensures that the parameters are passed to slice only if they were actually passed to the closure.

6502
  • 112,025
  • 15
  • 165
  • 265
  • AH! Calling slice instead of defining it yourself now makes perfect sense. But `Array.prototype.slice` vs `proto.slice` saves one lookup (not sure if that is the right word) total since we had to pass `Array.prototype` as a parameter first. We then call `ret.slice` and `ret.extend` which themselves are two lookups... So wouldn't this code run slower? – retrohacker Mar 30 '14 at 22:20
  • 1
    The lookup to create the closure is done only once. In your example instead it's done every time the function is called. – 6502 Mar 30 '14 at 22:21
  • Final question... Is there anything wrong with my logic in this test if we make proto a local variable? http://jsperf.com/palette-js-perf-test – retrohacker Mar 30 '14 at 22:27
  • @Crackers: seems to me you're measuring the time for creating the wrappers (something that is done only once), not the time to actually call them. – 6502 Mar 30 '14 at 22:30
  • you are entirely correct. I updated the tests. It shows no major difference in the performance of either on my browser. http://jsperf.com/palette-js-perf-test – retrohacker Mar 30 '14 at 22:44