Approaches to modular client-side Javascript without namespace pollution

后端 未结 8 1279
借酒劲吻你
借酒劲吻你 2021-02-02 02:14

I\'m writing client-side code and would like to write multiple, modular JS files that can interact while preventing global namespace pollution.

index.html



        
相关标签:
8条回答
  • 2021-02-02 02:38

    I strongly suggest you try a build tool.

    Build tools will allow you to have different files (even in different folders) when developing, and concatenating them at the end for debugging, testing or production. Even better, you won't need to add a library to your project, the build tool resides in different files and are not included in your release version.

    I use GruntJS, and basically it works like this. Suppose you have your util.js and index.js (which needs the helper object to be defined), both inside a js directory. You can develop both separately, and then concatenate both to an app.js file in the dist directory that will be loaded by your html. In Grunt you can specify something like:

    concat: {
        app: {
            src: ['js/util.js', 'js/index.js'],
            dest: 'dist/app.js'
        }
    }
    

    Which will automatically create the concatenation of the files. Additionally, you can minify them, lint them, and make any process you want to them too. You can also have them in completely different directories and still end up with one file packaged with your code in the right order. You can even trigger the process every time you save a file to save time.

    At the end, from HTML, you would only have to reference one file:

    <script src="dist/app.js"></script>
    

    Adding a file that resides in a different directory is very easy:

    concat: {
        app: {
            src: ['js/util.js', 'js/index.js', 'js/helpers/date/whatever.js'],
            dest: 'dist/app.js'
        }
    } 
    

    And your html will still only reference one file.

    Some other available tools that do the same are Brunch and Yeoman.

    -------- EDIT -----------

    Require JS (and some alternatives, such as Head JS) is a very popular AMD (Asynchronous Module Definition) which allows to simply specify dependencies. A build tool (e.g., Grunt) on the other hand, allows managing files and adding more functionalities without relying on an external library. On some occasions you can even use both.

    I think having the file dependencies / directory issues / build process separated from your code is the way to go. With build tools you have a clear view of your code and a completely separate place where you specify what to do with the files. It also provides a very scalable architecture, because it can work through structure changes or future needs (such as including LESS or CoffeeScript files).

    One last point, having a single file in production also means less HTTP overhead. Remember that minimizing the number of calls to the server is important. Having multiple files is very inefficient.

    Finally, this is a great article on AMD tools s build tools, worth a read.

    0 讨论(0)
  • 2021-02-02 02:38

    So called "global namespace pollution" is greatly over rated as an issue. I don't know about node.js, but in a typical DOM, there are hundreds of global variables by default. Name duplication is rarely an issue where names are chosen judiciously. Adding a few using script will not make the slightest difference. Using a pattern like:

    var mySpecialIdentifier = mySpecialIdentifier || {};
    

    means adding a single variable that can be the root of all your code. You can then add modules to your heart's content, e.g.

    mySpecialIdentifier.dom = {
        /* add dom methods */
    }
    (function(global, undefined) {
        if (!global.mySpecialIdentifier) global.mySpecialIdentifier = {};
        /* add methods that require feature testing */
    }(this));
    

    And so on.

    You can also use an "extend" function that does the testing and adding of base objects so you don't replicate that code and can add methods to base library objects easily from different files. Your library documentation should tell you if you are replicating names or functionality before it becomes an issue (and testing should tell you too).

    Your entire library can use a single global variable and can be easily extended or trimmed as you see fit. Finally, you aren't dependent on any third party code to solve a fairly trivial issue.

    0 讨论(0)
  • 2021-02-02 02:39

    One way of solving this is to have your components talk to each other using a "message bus". A Message (or event) consists of a category and a payload. Components can subscribe to messages of a certain category and can publish messages. This is quite easy to implement, but there are also some out of the box-solutions out there. While this is a neat solution, it also has a great impact on the architecture of your application.

    Here is an example implementation: http://pastebin.com/2KE25Par

    0 讨论(0)
  • 2021-02-02 02:44

    http://brunch.io/ should be one of the simplest ways if you want to write node-like modular code in your browser without async AMD hell. With it, you’re also able to require() your templates etc, not just JS files.

    There are a lot of skeletons (base applications) which you can use with it and it’s quite mature.

    Check the example application https://github.com/paulmillr/ostio to see some structure. As you may notice, it’s written in coffeescript, but if you want to write in js, you can — brunch doesn’t care about langs.

    0 讨论(0)
  • 2021-02-02 02:46

    You should check out browserify, which will process a modular JavaScript project into a single file. You can use require in it as you do in node.

    It even gives a bunch of the node.js libs like url, http and crypto.

    ADDITION: In my opinion, the pro of browserify is that it is simply to use and requires no own code - you can even use your already written node.js code with it. There's no boilerplate code or code change necessary at all, and it's as CommonJS-compliant as node.js is. It outputs a single .js that allows you to use require in your website code, too.

    There are two cons to this, IMHO: First is that two files that were compiled by browserify can override their require functions if they are included in the same website code, so you have to be careful there. Another is of course you have to run browserify every time to make change to the code. And of course, the module system code is always part of your compiled file.

    0 讨论(0)
  • 2021-02-02 02:51

    I would strongly recommend you to go ahead with RequireJS.


    The modules support approach (without requires/dependencies):

    // moduleA.js
    
    var MyApplication = (function(app) {
    
        app.util = app.util || {};
    
        app.util.hypotenuse = function(a, b) {
            return Math.sqrt(a * a + b * b);
        };
    
        return app;
    })(MyApplication || {});
    
    // ----------
    
    // moduleB.js
    
    var MyApplication = (function(app) {
    
        app.util = app.util || {};
    
        app.util.area = function(a, b) {
            return a * b / 2;
        };
    
        return app;
    })(MyApplication || {});
    
    // ----------
    
    // index.js - here you have to include both moduleA and moduleB manually
    // or write some loader
    
    var a = 3,
        b = 4;
    console.log('Hypotenuse: ', MyApplication.util.hypotenuse(a, b));
    console.log('Area: ', MyApplication.util.area(a, b));
    

    Here you're creating only one global variable (namespace) MyApplication, all other stuff is "nested" into it.

    Fiddle - http://jsfiddle.net/f0t0n/hmbb7/


    **One more approach that I used earlier in my projects - https://gist.github.com/4133310 But anyway I threw out all that stuff when started to use RequireJS.*

    0 讨论(0)
提交回复
热议问题