3

I am using the following namespacing pattern:

var MyNamespace = new function () {
    var foo = function () {
        bar();
    };
    var bar = function () {
        alert("bar");
    };
    this.init = function () {
        foo();
    };
};

$(document).ready(function() {
    MyNamespace.init();
});

JSLint complains that bar is used before it's defined. However foo is not called until after bar has been declared. The code works fine with all the browsers I have tried: http://jsfiddle.net/jDKvz/

The pattern is per How do I declare a namespace in JavaScript?, second answer.

Do I need to fix something here, or should I just ignore JSLint?

Community
  • 1
  • 1
Flash
  • 15,945
  • 13
  • 70
  • 98
  • Well presumably if you reverse the order of the two functions JSLint will be happy, but whether you "need" to do that is subjective. I don't agree with JSLint about everything, but in this case I'd probably just change the code to make it shut up. – nnnnnn May 10 '12 at 06:48
  • @nnnnnn My real project is far more complex, and possibly contains functions that call each other for example. – Flash May 10 '12 at 06:51
  • In that case I'd be quite happy to ignore JSLint on this point. Although I might try using `function foo() ...` syntax rather than `var foo = function()...` to see if it made any difference, because it's annoying having to remember which lint warnings/errors you have to actually care about... – nnnnnn May 10 '12 at 06:56
  • @Andrew what version of JSLint are you using? The [hosted version](http://www.jslint.com/) complains about `new function` being a "weird construction," but doesn't say bar is undefined. – Dagg Nabbit May 10 '12 at 08:19

3 Answers3

1

I suspect that's because of hoisting, variables and function declarations are hoisted onto top by the interpreter, it is likely that this is how it sees it:

var MyNamespace = new function () {
    var foo;
    var bar;

    foo = function () {
        bar();
    };

    bar = function () {
        alert("bar");
    };

    this.init = function () {
        foo();
    };
};

Now inside the foo = function () {bar();}; the bar() isn't yet parsed, it is just a variable bar not a function to be called at that point.

Having said that, if your code works fine, you can go with it, turning strict mode on is also helpful.

Sarfraz
  • 377,238
  • 77
  • 533
  • 578
0

Edit: Thought JS closed over values, not variables.

JSLint is complaining because it doesn't see the variable hoisting going on. Just define functions that are used by other functions before functions that use them. It helps make your code more readable, and shuts JSLint up.

For example:

var MyNamespace = new function () {
    var bar = function () {
        alert("bar");
    };

    var foo = function () {
        bar();
    };

    this.init = function () {
        foo();
    };
};
Havvy
  • 1,471
  • 14
  • 27
  • The "rules of closures"? Think again. _"is closed over the value undefined..."_ - closures close over _variables_, not over _values_. The code as shown in the question will work because `bar` is defined by the time `foo()` is called. Reversing the functions should shut up JSLint, but the original way isn't actually wrong. – nnnnnn May 10 '12 at 06:52
  • Alright, changed answer to be about readability than about the wrong closure stuff. I'm not going to tell somebody to use the function statement. – Havvy May 10 '12 at 06:58
0

bar is a function expression rather than a function declaration, meaning that it'll only work after it's being assigned. You can use a function declaration instead and jslint won't complain anymore.

function bar() {
    ...
}

Also, new Function is unnecessary , function is enough.

Edit:

Seems like in this case to get rid of new use an auto invoking function (function(){}()) or an object literal {}

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • 1
    It calls the following function as a constructor. – Havvy May 10 '12 at 06:46
  • what about `(function(){ ... }())` – elclanrs May 10 '12 at 06:47
  • That can also work, and is what I prefer, but new can also be used here. – Havvy May 10 '12 at 06:49
  • `(function(){ ... }())` wouldn't work here, the constructor function returns nothing. – KooiInc May 10 '12 at 06:53
  • Regarding the first sentence in this answer, the code in the question works as is because `bar` _is_ assigned by the time it is actually used. The problem here is the difference between code that works and code that JSLint is completely happy with. – nnnnnn May 10 '12 at 06:58
  • **@nnnnnn** I dont think it has to do with jslint in this case. I mean, a function expression or assignment will only ever work after being created. The function declaration will work everywhere. – elclanrs May 10 '12 at 07:02
  • The code in the question works as is. Through variable declaration hoisting `bar` exists but is undefined at the time `foo` is assigned to its function expression, but by the time `foo()` is actually _called_ `bar` also refers to a function. – nnnnnn May 10 '12 at 07:05
  • That's browsers being smart but jslint is based on better practices rather than "whatever works". jshint is more forgiving. – elclanrs May 10 '12 at 07:08
  • Sorry, I didn't intend to turn this into a debate (so I'll make this my last comment), but this isn't just browsers being smart, it is the way JS is supposed to work. `bar` could be reassigned repeatedly at runtime to point to different functions, but `foo()` will work as long as `bar` actually references _some_ function at the point when `foo()` is called. (Conversely even if `bar` were assigned first it could be reassigned to undefined before `foo()` is called.) But yes, just because something can work according to the language spec doesn't necessarily mean it is a good practice. – nnnnnn May 10 '12 at 07:30