5

I have ignored javascript forever. I started using jQuery a few years back so I could get by. But as I've started doing TDD more I decided yesterday to really dive into javascript (and possibly coffeescript after that).

In my ASP.NET Web Forms application I have many pages and currently most of those pages do not have a ton of javascript. I'm in the process of changing that. I'm using Jasmine with Chutzpah to create my tests.

I was moving along with my tests passing and failing as expected. But then I wanted to create a namespace so I wouldn't be trampling all over global space.

After reading this article: http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/

I decided to try and use the pattern from the Self-Executing Anonymous Function: Part 2 (Public & Private) section of the article. It appears to have the most flexibility and appears to encapsulate things very well.

I have a folder called /Scripts. Under that folder are some of the frameworks I'm using like jQuery, jasmine, (twitter) bootstrap and modernizr. I also have a subfolder called /Site where I am putting my code for the site in multiple files based on the page. (product.js, billing.js, etc.)

Under /Scripts/Site I added a subfolder to /Tests (or Specs) that have the files (product_test.js, billing_tests.js, etc.).

Without having namespaces everything is fine. I have a utility.js file I created with a padLeft helper function. I then used that global padLeft in another .js file. My tests all worked and I was happy. I then decided to figure out the namespace and changed my Scripts/Site/utility.js to look like:

(function (myns, $, undefined) {
    //private property
    var isSomething = true;

    //public property
    myns.something = "something";

    //public method
    myns.padLeft = function (str, len, pad) {
        str = Array(len + 1 - str.length).join(pad) + str;

        return str;
    };


    //check to see if myns exists in global space
    //if not, assign it a new Object Literal
}(window.myns= window.myns|| {}, jQuery ));

Then in my Scripts/Site/Tests/utility_test.js I have

/// <reference path="../utility.js" />

describe("Namespace myns with public property something", function () {
    it("Should Equal 'something'", function () {
        expect(myns.something).toEqual('something');
    });
});

With this extremely simple test I was expecting myns.something to come back with the string value of 'something'.

It doesn't. It comes back undefined.

So, how do I to use javascript namespace across multiple files?

Sorry for the long introduction, but I figured it may help explain the why of me doing it this way. I also put all of this because I'm open to hearing ideas about how this setup is totally wrong or partially wrong or whatever.

Thanks for taking the time to read this question.

UPDATE: SOLVED Thank you all for your help. The most help came from the commenter @T.J. Crowder. I didn't know the jsbin tool existed and after being convinced that the code I put above was put into the tool and the results were right I knew something had to be off in my environment.

The link in the accepted answer also helped me out a lot. After seeing that the syntax and logic was consistent and working I just had to determine what was off about my setup. I'm embarrassed to say it was me passing in jQuery but in my test harness where I was trying to get this to work I wasn't actually using jQuery. This meant the module wasn't actually being loaded - so myns was never set.

Thanks everyone. Hopefully this may be helpful to someone in the future. If you use the above make sure you include the jQuery object. The other option is to not pass in jQuery and remove the $ from the param list.

Chad Carter
  • 1,938
  • 2
  • 16
  • 16
  • 2
    What you've shown should work provided both `utility.js` and `utility_test.js` are included, and in that order. Example: http://jsbin.com/idofog – T.J. Crowder Apr 17 '12 at 13:02
  • thank you for the long introduction, it's helping us to figure out what you want :-) – Philipp Apr 17 '12 at 13:04
  • @T.J.Crowder Thanks. That bin works but I can't see why it is different in my environment. I didn't know about jsbin, so thanks for that as well! I'm going to try a few things in that sandbox. – Chad Carter Apr 17 '12 at 13:39
  • Here's a really good article on the module pattern (what you're using here) that goes into implementing it across files: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth – Keith Rousseau Apr 17 '12 at 13:01

2 Answers2

1

Try putting your name space declaration outside of the function call:

myns = window.myns || {};
(function(myns, $, undefined) {
    ...
}(myns, jQuery));

Your existing syntax appears to be completely valid, but breaking that line out may help figure out what's going wrong with your variable scope.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
0

Javascript does not have namespaces, i guess you have troubles with variable scopes and this is similar to other languages, what you are talking about are objects. You could use

window.myns.something

The first function is already adding your object to the window object, and the window object is accessible from anywhere.

Philipp
  • 1,425
  • 1
  • 11
  • 23
  • using a nested property like this is a common way of emulating namespaces in Javascript. – Alnitak Apr 17 '12 at 13:07
  • I know but as you said, it's "emulating" namespaces. There are huge differences to namespaces e.g. in .NET, but it's similar to objects in .NET (except changing the interface at run time) – Philipp Apr 17 '12 at 13:09
  • @PhilippMehrwald Thanks. I should have been more clear about stating "emulating namespaces". With the pattern I'm after I'm trying to avoid using window.myns.something. Even changing it to that in my test file failed. So I must have something else wrong. Thanks! – Chad Carter Apr 17 '12 at 13:44
  • Where is myns originally defined? – Philipp Apr 17 '12 at 13:48
  • @PhilippMehrwald it is currently defined in Script\utilities.js at the bottom of the first code block: window.myns= window.myns|| {}, – Chad Carter Apr 17 '12 at 13:59