14

I'm studying the annotated source code of Underscore.js.

http://underscorejs.org/docs/underscore.html#section-41

Here's the _.first method:

  _.first = _.head = _.take = function(array, n, guard) {
    if (array == null) return void 0;
    return (n == null) || guard ? array[0] : slice.call(array, 0, n);
  };

Question:

Why 'return void 0;' and not just 'return;' ? As far as I know return implicitly returns undefined (the value!) from a function. Just like 'return void 0' does.

Lukasz Prus
  • 343
  • 1
  • 5
  • 10
  • 5
    it appears to be an inconsistency, as in other parts of the source `return;` is used. – zzzzBov Oct 18 '13 at 15:56
  • Probably to make the code clearer. – Denys Séguret Oct 18 '13 at 15:56
  • 1
    it might be one of those things that can never be explained. (even if you asked the programmer who wrote it) – Hassan Hayat Oct 18 '13 at 15:57
  • On [2010-12-01](https://github.com/jashkenas/underscore/commit/2d06e1d5262ca2e17aa71955c7780d15acc18d5d#diff-0f36b362a0b81d6f4d4bfd8a7413c75d) the author added `return;` to the code for the first time, and `return void 0;` appeared [2012-10-06](https://github.com/jashkenas/underscore/commit/a9ce927465f044cb1be22f96c2bf9752c23d15b4`). Chalk it up to the passage of two years' time? – apsillers Oct 18 '13 at 16:26

1 Answers1

10

In the MDN reference for the void operator it states:

The void operator is often used merely to obtain the undefined primitive value, usually using "void(0)" (which is equivalent to "void 0"). In these cases, the global variable undefined can be used instead (assuming it has not been assigned to a non-default value).

So it is indeed equivalent to undefined but the problem with the undefined variable is that it can be redefined as something else. Personally I would always simply return; because it consistently yields the exact same result (as in: (function() {})() === void 0).

Clarification

Since some commenter consider this not an appropriate answer:

(function() {})() === void 0 always yields true which means that it is exactly the same as return;. So you can consider this an inconsistency in the Underscore library as plain return statements are used in other places (yes, even there it can happen).

Minification and optimization

Another addendum, it looks as if it also doesn't optimize any better during minification. Using the closure compiler the return void 0; vs return; version of the above code sample is still about 5% bigger.

Daff
  • 43,734
  • 9
  • 106
  • 120
  • What do you mean by saying that `undefined` can be reassigned? If I try `var undefined = 2` or even the naughty global `undefined = 2` and then recall `undefined`, I get ... `undefined`! Is this what you meant? – guypursey Oct 18 '13 at 16:00
  • 2
    Using return without undefined, the reassignement problem can't occur. This doesn't seem to answer at all. – Denys Séguret Oct 18 '13 at 16:01
  • 2
    @guypursey The lexical identifier `undefined` can be used in a non-global scope as a variable name: `(function() { var undefined = "foo"; console.log(undefined); })()` – apsillers Oct 18 '13 at 16:02
  • 1
    Here is a Fiddle of what I mean: http://jsfiddle.net/dXjFy/ reassigned was probably the wrong term, it should be redefined. – Daff Oct 18 '13 at 16:02
  • 1
    +1 to apsillers and Daff Was not aware of this possibility so thank you! However @dystroy is right; it doesn't answer the OP's question. – guypursey Oct 18 '13 at 16:07
  • I think it answers the question in the sense that it doesn't make a difference – Ingo Bürk Oct 18 '13 at 16:10
  • 1
    As Ingo said, I think it does stating that `(function() {})() === void 0` (which is always true for any JS engine I tried). So it simply doesn't make a difference and shows that even libraries like underscore can have inconsistencies. – Daff Oct 18 '13 at 16:11
  • … and frankly I think the only "real" answer to why it was used could only come from the person writing it. We can only guess intentions, not know them. But as far as the technical side goes, Daff answered it fully. I've been reading this question and answer several times now and can't for the life of me figure out why the answer gets down-voted while an easily searchable question gets so many upvotes. Some things are just beyond me. :) – Ingo Bürk Oct 18 '13 at 16:19
  • 2
    @guypursey Yes, you can change the value of the global variable **undefined** in earlier versions of ECMAScript. See the note on [mozilla's reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined). It says _Starting in JavaScript 1.8.5 (Firefox 4), undefined is non-writable, as per the ECMAScript 5 specification._ – Lukasz Prus Oct 18 '13 at 19:18
  • @Daff Thanks! My only concern was if `(function() {})()` returns the primitive value undefined or the value of the variable `undefined` (which can be overwritten, see my previous comment). I tested that in old Firefox (which allows undefined variable to be overwritten) and got that in fact `(function() {})()` returns the primitive value. – Lukasz Prus Oct 21 '13 at 14:40
  • 4
    I also asked the creators https://github.com/jashkenas/underscore/issues/1315#issuecomment-26621870. So it all looks like inconsistency. A simple `return;` would do. – Lukasz Prus Oct 21 '13 at 14:43