3

I have tweaked a Javascript Ninja book's code example (listing 6.9) a bit to make it even shorter. This code snippet is about adding a forEach method to Array.prototype (I renamed it fooEach to avoid confusion). Now the question: Why do we need to pass (context || null) as the first parameter (null in the code example)? Function.call method has its first argument -- the context -- optional, so why is it a must to pass the context as the first parameter in this case?

if (!Array.prototype.fooEach) {                                
    Array.prototype.fooEach = function(callback, context) {      
        for (var i = 0; i < this.length; i++) {
            callback.call(context || null, this[i], i, this);       
        }
    };
}
["a", "b", "c"].fooEach(function(value, index, array) {        
    console.log(value + " is in position " + index + " out of " + (array.length - 1));
});
juniorNinja
  • 55
  • 1
  • 5
  • it sets the `this` inside of the function. – Daniel A. White Jul 20 '14 at 21:19
  • 1
    @DanielA.White — And why is `null` better than `undefined` or `0`? – Quentin Jul 20 '14 at 21:20
  • @DanielA.White: The OP asks why they pass `context || null` rather than just `context`. This deserves an explanation, not just closing. – Wiktor Zychla Jul 20 '14 at 21:24
  • 1
    Seeing that the question was closed as a duplicate (why?), I cannot post an answer. The first argument is "optional" in the sense that if you do not have any value to pass to it, pass `null` or `undefined`. JavaScript has no concept of keyword arguments and due to the types of the other arguments, it's not possible to figure out if the first argument has been skipped. – Blender Jul 20 '14 at 21:26
  • Thanks @Blender! This was exactly my confusion. I though "optional" means "may not be there", and obviously was puzzled how the call method can figure out if we pass this first argument to it or not. – juniorNinja Jul 20 '14 at 21:36
  • Blender's got it right. – alex Jul 21 '14 at 00:39

1 Answers1

1

Function.call method has its first argument -- the context -- optional, so why is it a must to pass the context as the first parameter in this case?

Because .call() is a variadic function; it accepts an unknown number of arguments, so any fixed arguments (or arguments with different semantics from the others) are placed at the front.

Specifying either undefined or null as the first argument will replace this inside the function you're calling with the global object (in non-strict mode).

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • Thanks! The confusion was about the meaning of "optional" for the 1-st ("context") argument. I assumed it's optional for the coder to put it there or not based on the logic of the code. This assumption brought an even greater puzzle -- how .call knows if the 1-st argument passed to it is a context, or smth else?! Now it's all clear -- one always has to pass the context value, even if it's null. – juniorNinja Jul 21 '14 at 01:11
  • @juniorNinja If there are no arguments, you can just do `.call()` as well; in strict mode it will turn `this` into `undefined` though :) – Ja͢ck Jul 21 '14 at 01:12