Pierre Arlaud
Pierre Arlaud

Reputation: 4133

Is passing undefined equivalent to passing no argument?

Curiously,

['a', 'b', 'c'].lastIndexOf('b', undefined)

returns -1 while the following:

['a', 'b', 'c'].lastIndexOf('b')

returns 1 (at least on Firefox 65's scratchpad).

I assumed passing undefined would have the same result as passing no argument.

However it seems

['a', 'b', 'c'].lastIndexOf('a', undefined)

does return 0 as expected, which makes me believe my undefined gets converted to 0.

I understand the default value of the index parameter in lastIndexOf points to the last element of the array. But shouldn't passing undefined have the same behaviour as passing no argument?

Upvotes: 3

Views: 1095

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

I previously wrote a comment explaining that, according to the polyfill at MDN, the undefined as the second argument of Array.prototype.lastIndexOf (in the polyfill the parameter named n) indeed gets converted to 0 by these steps:

  1. n = Number(undefined) => converts undefined to NaN.
  2. if(n != n) n = 0 => checks for NaN and converts it to 0.

let n = Number(undefined);
if (n != n) n = 0;
console.log(n);

Since this is just the polyfill at MDN it seemed to me that it wasn't worth a proper answer. However, the spec at ECMA-International says the same about Array.prototype.lastIndexOf(searchElement[,fromIndex]):

If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be len-1.

Where len-1 is obviously the last index of the array. Then, we have at ToInteger:

  1. Let number be ToNumber(argument).
  2. ReturnIfAbrupt(number).
  3. If number is NaN, return +0.

In conclusion, your undefined gets converted to 0 and, therefore, passing undefined as the second argument of Array.prototype.lastIndexOf is different from passing nothing.

EDIT

Given your last comment I reckon that the cause of your misunderstanding is clear. You see, there is no default parameter here, and this whole issue has nothing to do with it. Let me explain:

As you know, in JavaScript we can pass more arguments than parameters or less arguments than parameters. If we pass too few arguments, the missing parameters are undefined. This is easy to show:

function foo(parameter1, parameter2) {
  console.log("parameter 2 is " + parameter2)
};
foo("bar");
foo("bar", undefined);

As you can see, passing nothing or passing undefined has the same effect. However, this is not what's happening here. In the polyfill the function uses the pseudo argument array-like arguments to get the second argument, testing for arguments.length > 1. Therefore, when you say...

Does undefined count as a passed argument? I thought it didn't.

It does when you take into account the length of the arguments array-like object. And, in that case, the difference does matter:

function foo(parameter1, parameter2) {
  if (arguments.length > 1) {
    console.log("parameter 2 is " + arguments[1])
  } else {
    console.log("no second parameter")
  }
};
foo("bar");
foo("bar", undefined);

Upvotes: 3

Related Questions