I have a JavaScript snippet with a recursive function call:
(function () {
"use strict";
var recurse = function (x) {
if (x <= 0) {
return;
}
return recurse(x - 1);
};
recurse(3);
}());
This does nothing but call itself a few times, but it runs.
Pasting the above into JSLint gives me this error:
'recurse' is out of scope.
However, if I paste in the following snippet, (using a function declaration instead of var):
(function () {
"use strict";
function recurse(x) {
if (x <= 0) {
return;
}
return recurse(x - 1);
}
recurse(3);
}());
JSLint loves it, no errors.
I know that the goal of JSLint is to prevent bugs in JavaScript code. Does anyone know why JSLint thinks the first one is bad JavaScript? What bug am I preventing by not making a recursive call in the first way?
EDIT: To any future visitors to this question: Neither of these JavaScript snippets throw any errors in the latest version of JSLint.
The " {a} used out of scope" error (and the alternative " {a} used outside of binding context" error) are thrown when JSLint, JSHint or ESLint encounters a reference to a variable declared in an inner block. In the following example we declare the variable x in the body of an if statement and then attempt to return it from the enclosing function:
JSLint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily a syntax error, although it often is. JSLint looks at some style conventions as well as structural problems.
In JavaScript, void is a prefix operator that always returns undefined. JSLint does not expect to see void because it is confusing and not very useful. Regular expressions are written in a terse and cryptic notation. JSLint looks for problems that may cause portability problems.
If you neglect to use the new prefix, no new object will be made and this will be bound to the global object. JSLint enforces the convention that constructor functions be given names with initial uppercase. JSLint does not expect to see a function invocation with an initial uppercase name unless it has the new prefix.
There is nothing wrong with either style. As far as I can tell, this is an inappropriate warning.
The issue appears to be that a variable declaration that includes an assignment does not cause JSLint to register the presence of the declared variable name in scope until the entire assignment is evaluated. That is, when JSLint reads var recurse = ...
, it does not realize recurse
is a declared variable until after it evaluates the right-hand side of the assignment. In this case, the right-hand side includes a function that makes use of the declared variable recurse
, but JSLint didn't know about the existence of recurse
yet, because it hadn't finished parsing the entire assignment.
Consider that this code works exactly the same as your var
example but produces no warnings in JSLint:
(function () {
"use strict";
var recurse;
recurse = function (x) {
if (x <= 0) {
return;
}
return recurse(x - 1);
};
recurse(3);
}());
By drawing out var recurse
as a separate statement, JSLint first learns that recurse
is declared in the current scope, and then parses the assignment. With your combined var recurse = ...
(which, again, is not wrong), JSLint erroneously parses the assignment first and then learns about the existence of recurse
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With