Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There are a few quick problems I can see.</p> <p>Consider this:</p> <pre><code>var car = {}; car.manufacturer = "Toyota"; car.doors = 4; car.format = "sedan"; car.wheels = 4; </code></pre> <p>There's a lot of repetition going on, here.<br> If you were to try making this a further-nested object, but continue defining properties this way, that would be a LOT of either retyping or copy/pasting.</p> <pre><code>var garage = {}; garage.cars = []; garage.cars[0] = {}; garage.cars[0].doors = 4; garage.cars[0].drivers = []; garage.cars[0].drivers[0].name = "Bob"; </code></pre> <p>...et cetera.</p> <p>The first issue here is that it would become pretty easy to miss out on details, in one form or another. There are so many lines, and so much repetition that perhaps on line 37, you forget to initialize <code>cars[3].drivers[1].license_number</code>.</p> <p>The second issue is that if you break up this initialization, but attempt to initialize in an order which is poorly-defined (ie: doing this over multiple JS files, or doing it over multiple AJAX calls), then you run the risk of hitting an exception, when you try to add a property to a member which doesn't yet exist.</p> <p>// core js var MyApp = {}; MyApp.modules = {};</p> <p>// js #2 loaded before js #1 MyApp.modules.myModule.subModule = {}; // will throw an exception</p> <p>// js #1 MyApp.modules.myModule = {};</p> <p>There are ways of getting around this, but they all depend on what you're hoping to achieve:</p> <p>If you are looking at building data-structures which have static default values, then I'd suggest building a simple data-structure like this:</p> <pre><code>var car = { doors : 4, manufacturer : "Toyota" }; </code></pre> <p>Or a more elaborate object like this: </p> <pre><code>var garage = { cars : [ { doors : 2, drivers : [ { name : "Bob", age : 32 }, { name : "Susanne", age : 18 } ] } ] }; </code></pre> <p>They can still easily be referenced like so:</p> <pre><code>garage.cars[0].drivers[1].name; // Susanne </code></pre> <p>If you are building modules of functionality, like a library, then namespacing is still a good idea.<br> Do so in either way presented in the other answers. </p> <p>systematically-checking:</p> <pre><code>if (MyApp &amp;&amp; MyApp.modules.myModule) { MyApp.modules.myModule.subModule = { send : function () { } }; } </code></pre> <p>Or building a function which you can use like: </p> <pre><code>namespace("MyApp.modules.myModule.subModule.addOn", { method : function () {}, property_1 : 1, property_2 : false }); </code></pre> <p>Which could then split the string and check if each name existed, and create them if they don't.</p> <p>Also, don't use <code>document.write</code>. Browsers now do a good job of preventing it from screwing up sites, but you should use <code>console.log</code> for logging purposes, or DOM-manipulation (or <code>.innerHTML</code>, if need be) for writing to the page.</p> <p>Also <code>that</code> doesn't really do what you think it might.<br> The problem with <code>this</code> is if you have a function inside of another function, <code>this</code> will become <code>window</code>, instead of staying the same as before. </p> <p>An example: </p> <pre><code>function decrease_fuel () { this.fuel -= 1; } var car = { fuel : 100, speed : 10, pos : { long : ..., lat : ... }, dir : { long : ..., lat : ... }, drive : function () { if (this.fuel &gt; 0) { this.pos.long += this.dir.long * this.speed; this.pos.lat += this.dir.lat * this.speed; decrease_fuel(); // whoops! `this === window` // decrease_fuel.call(this); would work } } }; </code></pre> <p>So if you were to create a function where you wanted the inner-scope to point to the same <code>this</code> as the outer, you would use a variable which saves the value of the outer <code>this</code>, for the inner to reference through closure.</p> <pre><code>var outer = function () { var that = this, inner = function () { console.log(that); }; inner(); }; outer.call({ name : "Bob" }); // logs bob object </code></pre> <p>If the line in <code>inner</code> was <code>console.log(this);</code>, then:</p> <pre><code>outer.call({ name : "Bob" }); // would log `window` object </code></pre> <p>As for <code>namespacing</code> versus <code>requireJS</code>, they're both the same thing, in a way.<br> Where they differ is in what they're used for.<br> <code>requireJS</code> is meant to be used to load multiple files, and to ensure that they're loaded in the right order. And if you define namespaces, using requireJS, then they will be namespaced, when the loading is done. </p> <p>With a simple namespace function, it would be up to you to load individual components, in the way your project agreed on, and then in each file, use the namespacing function to add each module. </p> <p>If you only plan on having one JS file, then requireJS doesn't offer much benefit over the other.<br> If you're going to have multiple JS files (one per module, in the same way you might break out classes in Java), then <code>requireJS</code> offers benefits, at the cost of requiring you to learn the interface.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload