6

JSLint seems to be picky about function ordering.

This passes fine:

function a() {
    'use strict';
    return 1;
}

function b() {
    'use strict';
    a();
}

While this gives an 'a' is out of scope error message:

function b() {
    'use strict';
    a();
}

function a() {
    'use strict';
    return 1;
}

Is this by design? Should I care? How can it be avoided in larger (more complex) cases, where it might not always be possible to give the functions a clear order?

Codemonkey
  • 4,455
  • 5
  • 44
  • 76
  • The error should be something like, `Functions should be defined before using them` – Tushar Jan 05 '16 at 14:50
  • 2
    "JSLint seems to be picky about function ordering." — Yes, it is. For that matter… "JSLint seems to be picky" is true as well. – Quentin Jan 05 '16 at 14:51
  • Some linters want you to define functions before they are referenced, JavaScript doesn't care though. – Ruan Mendes Jan 05 '16 at 14:53
  • 2
    http://stackoverflow.com/questions/7609276/javascript-function-order-why-does-it-matter – epascarello Jan 05 '16 at 14:54
  • The comment from @epascarello is absolutely essential here. This ordering warning really is an error worth addressing (see answer, below). Also, do you have an example of "where it might not always be possible to give the functions a clear order"? Usually, as I remark below, that's a code smell worth checking out. – ruffin Jan 05 '16 at 15:34

2 Answers2

4

JSLint/JSHint expect you to define functions before you reference them. However, JavaScript doesn't care because functions and variables are hoisted.

You can change your code style, or tell the linter to ignore it using http://jshint.com/docs/options/#latedef

/* jshint latedef:nofunc */
function b() {
    'use strict';
    a();
}

function a() {
    'use strict';
    return 1;
}

See https://stackoverflow.com/a/23916719/227299

Community
  • 1
  • 1
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • 2
    Worth noting `latedef:nofunc` is a JSHint-only directive. – ruffin Jan 05 '16 at 15:35
  • @ruffin [This answer](http://stackoverflow.com/a/9512299/227299) seems to imply that it's also on JSLint `/*jslint latedef:false*/` – Ruan Mendes Jan 05 '16 at 15:39
  • 3
    Hrm. It doesn't work on jslint.com now, and I don't see it in the [instructions](http://jslint.com/help.html) either. Now JSLint changed a lot last year when Crockford updated to ES6, but I [don't see that in the old instructions](https://web.archive.org/web/20140312234140/http://www.jslint.com/lint.html) (I checked a few dates) either, as [some comments](http://stackoverflow.com/questions/806163/jslint-using-a-function-before-its-defined-error/9512299#comment19095210_9512299) there suggest. Perhaps it's in an odd (*qua* strange & rare) version, or that answer was posted in error. – ruffin Jan 05 '16 at 15:45
1

@epascarello's link to where this was discussed for JSHint really is absolutely essentially here, because this isn't just a question of style.

Let's hit the high points of the excellent answer at that question, as it applies to JSLint as well.*

There are two ways to define functions: Function declaration and function expression. The difference is annoying and minute, so let's just say this slightly wrong thing: If you're writing it like function name() {}, it's a declaration, and when you write it like var name = function() {} (or an anonymous function assigned to a return, things like that), it's a function expression.

bar(); //This won't throw an error
function bar() {}

foo(); //This **WILL** throw an error
var foo = function() {}

[emphasis mine -r]

It really is worth reading all of the answer there, but it's also worth emphasizing that this JSLint error isn't just about style, it's warning you about the possibility of a functional error. Edge-case-y, sure, but a useful habit.

I'll also add that there shouldn't be a case where you have to recursively call functions in JavaScript that exist before they're defined. I've been annoyed when I've seen this error in that context a few times, but it's [almost?] always helpfully shown some code smell where a refactoring was useful rather than a place where all the function jumping is required.

It seems like you might be able to cheat around the warning if you jump a lot with function namespacing, which I may have embarrassingly done in a case or two. I hope not (on both counts), though.


* I was tempted to add JSLint to that question and call this one a dupe, but wasn't sure that was quite kosher.

Community
  • 1
  • 1
ruffin
  • 16,507
  • 9
  • 88
  • 138
  • Interestingly JSHint didn't complain for me at all, only JSLint did. – Codemonkey Jan 05 '16 at 16:13
  • Did the suggested directive in the answer you accepted change anything for you in JSLint? Or is the answer for you here simply to use JSHint? It's worth following the rule, I believe -- though, as always, don't bother linting your trusted 3rd party libraries! That's often a quick path to insanity. ;^) – ruffin Jan 05 '16 at 18:11