Code patterns for JavaScript libraries - javascript

Among JavaScript libraries (jQuery, MathJax, marked Markdown rendering library, etc.), I often see various patterns:
Pattern #1
index.html
...
<script src="mylibrary.js"></script>
</body>
</html>
mylibrary.js
var mylibrary = (function() {
...
var myVar = ...
...
})();
Pattern #2
index.html
<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
</body>
</html>
Same mylibrary.js
Pattern #3
index.html
<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
<script>
mylibrary.run(); // explicitly needs to be run
</script>
</body>
</html>
Same mylibrary.js
Questions:
What's the purpose of the var mylibrary = (function() { ... })(); trick?
Is there a difference between pattern #1 and #2? (I would say no)
Is there any reason to prefer #3 rather than #2?
It seems that both could be interesting. Example for MathJax: pattern #2 makes sense (it would autoparse the DOM and render math formulas), it's what has been chosen by them (see this example). Pattern #3, requiring an action to actually run the rendering would make sense as well.

The purpose of that is that it's creating a modularized IIFE (Immediately Invoked Function Expression). This is useful to avoid polluting/assigning variables to the global namespace and helps prevent conflicts with other external plugins/dependencies that might appear in your app.
Yes. In the first your scripts are loaded in the head whereas your scripts are loaded in before the closing of the body in #2. It's recommend to load your scripts before the closing of the body so your page doesn't hang as it loads in your javascript files.
Go with #3 over #2. As to why, refer to point #1.
Update
Here's an example of how things would look if you were to simply assign a variable within the global namespace.
var exampleGlobal = "I'm an example global variable";
function one() {
exampleGlobal = 1;
}
....
function two() {
exampleGlobal.charAt(0);
}
one(); // Changes the exampleGlobal to a Number
two(); // Tries to use a string-based instance method but throws an error since exampleGlobal is now a number
Here we see that the exampleGlobal is exposed and available to all functions within this script. In this case it's very easy to err and change the value/purpose of this variable anywhere in your script. Here's where IIFE's come into play:
var exampleModule = (function() {
var privatized = "I'm only accessible within this module";
return {
privatized: privatized
}
}());
In the above we're creating just but one global variable that serves as a module and encapsulates values/functions that would only pertain exclusively to it. Try accessing privatized globally. You'll find that it returns undefined as it's not available within the global scope unless you explicitly invoke the module and it's return value:
var exampleModule = (function() {...}());
console.log(privatized); // undefined
console.log(exampleModule.privatized); // returns: "I'm only accessible within this module"
IIFE's are also advantageous in the fact that you can safely avoid naming conflicts that may occur within your app. As an example, jQuery and Mootools share the $ character to invoke their respective function calls. If you'd like to safely use the jQuery without any conflicts with Mootools you pass the $ object as an argument into your IIFE, which will then shield it from the global scope.
(function($) { // Here this is just the parameter we'd like to refer jQuery as
$('div');
}(jQuery)); // You pass in the actual jQuery object here which is when/where the function is immediately invoked.

You can't access myVar outside mylibrary.
See Should I write script in the body or the head of the html?
Pattern #3 gives you more control of when and how you actually use mylibrary.

Related

How to use function declared in different JS file using jQuery getScript?

I have two JS files. One is called common.js and it use $.getScript to include other file with my js code. Part of including looks like this:
jQuery.getScript(js_path + "table.js", function(){
generateTable(chartData, dataTypes);
});
This file (common.js) also contains function compare(a, b).
Now, the second one (table.js) has declared different function which uses the compare function from the first file. Something like this:
function someName() {
var a = 2,
b = 5;
var test = compare(a, b);
return test;
}
When I run the code it gives me:
Uncaught ReferenceError: compare is not defined
How can I use function from the first file.
jQuery.getScript first fetches the JS file from the server, then executes it. If you want to work with global functions (as it seems) you need to pay attention to the following:
Your compare function must be declared before the table.js file is executed.
The compare function must be declared on the global namespace of table.js.
Sorry but without more info this is all you can get.
If your main file, as something like:
(function() {
function compare(){...}
}());
Then the compare function is not declared in the global namespace.
did you check the order of imports? The file with 'compare' method should be first. It should solve the problem.
What I would suggest is to skip getScript if it's just for separating the code.
<script src="common.js"></script>
<script src="table.js"></script>
<script src="app.js"></script>
Where common functions go into common, your table stuff goes into table. This way you get the ordering right. This also clears out the circular dependency one might see a hint of if table depends on common that depends on table by extracting all but the 'common' parts into some form of 'app'.

JavaScript 'Import' a module into another module

I'm currently messing around with JavaScript to try and understand the language more. I want to make two different modules, one with generic helper functions and the other with specific functions to the problem.
How can I access functions from one module to another?
You have two options here. Both are fairly popular, so it's up to you which you choose.
The first is to define your helper module in the scope of your application module's parent:
var helpMod = (function(){
return {foo:"bar"}
})();
var appMod = (function(){
console.log(helpMod.foo);
})()
And the second is to directly import the module as a parameter to the closure function:
var helpMod = (function(){
return {foo:"bar"}
})();
var appMod = (function(h){
console.log(h.foo);
})(helpMod);
Direct imports are more explicit, but taking advantage of scoping can be easier - so long as you're comfortable with that variable in the global scope!
You would simply place the various functions into two separate files then reference them in a "sandbox" HTML page as follows:
helper.js
function helper_function() {
alert("this is a helper function");
}
specific.js
function specific_function() {
alert("this is a specific function");
}
index.html
<html>
<head>
<script src="helper.js"></script>
<script src="specific.js"></script>
</head>
<body>
<script type="text/javascript">
helper_function();
specific_function();
</script>
</body>
</html>

javascript linking

I'm going to build a rather complicated application in html5 with some heavy javascripting.
In this I need to make some objects which can be pass around. But since there is no like #import foobar.js.
Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
I read (here) that ajax somehow is able to load a .js file from within another .js file. But i dont think this is what I need?
Can go more into details if needed, thanks in advance.
In our projects, we do the following: Suppose you're going to call your project Foo, and have a module called Bar in it,
Then what we do is declare a file called Foo.js that just defines an equivalent to a Foo namespace:
Foo = (function(){
return {
};
})();
Then we create a file called Foo.Bar.js that contains the code for the Bar module:
Foo.Bar = (function(){
// var declarations here that should be invisible outside Foo.Bar
var p, q;
return {
fun1 : function(a, b){
// Code for fun1 here
},
fun2 : function(c) {
// Code for fun2 here
}
} // return
})();
Note that how it is a function that executes immediately, and returns an object that gets assigned to Foo.Bar. Any local variables, like p and q are available to fun1 and fun2 because they're in a closure, but they are invisible outside of Foo.Bar
The functions in Foo.Bar can be constructors for objects and so on.
Now in your HTML you simple include both files like so:
<script type="text/javascript" src="Foo.js"></script>
<script type="text/javascript" src="Foo.Bar.js"></script>
The result will be that you can call Foo.Bar's functions in the JavaScript of your main HTML file without any problems.
You should check out the module pattern:
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth/
This describes alternatives for creating modular code in javascript, how you can protect your code and share APIs and data among them.
You should also consider using and AMD. Require.js is quite popular, but I tend to prefer head.js for this. Keep in mind that these put some requirements on how you structur your code in files, and personally, I don't think it's worth it, compared to a concatenated and minified file included in the bottom of the page.
Then I assume that if my html page loads the scripts, then all the scripts can access eachother?
Yes.

calling a javascript function from a separate script?

I want to organize my JavaScript so I thought I would make a functions JS file. Is there anyway I can call the functions from functions.js from global.js?
EDIT
functions.js:
var get_selects;
get_selects = {
getLanguages: function() {
}
}
global.js:
get_selects.getLangueges();
Yes, functions defined at the top level are automatically available in the global scope (window in a browser), and this is typically not desirable.
Another approach that would mitigate this is to group your functions into a single object so you aren't polluting the global scope with a whole bunch of unrelated functions.
var utils;
utils = {
toast: function(message) {
alert("Notification: " + message);
},
sum: function(a, b){ return a + b; }
}
utils.toast('Email sent');
utils.sum(1, 2);
If both scripts have been included in the same HTML file, sure, it will work out of the box. Best way to know is to try it.
All .js files load top level functions into the global namespace. So, yes.
simply call it like anyother functions
yourFunctionName(yourFunctionParams);
be aware, you need to include your functions.js BEFORE your global.js, else it won't see your functions.
From the moment you include a JS in the HTML file, all the functions become available. So, if you make like this, it will work:
<script type="text/javascript" src="functions.js"></script>
<script type="text/javascript" src="global.js"></script>
But (as soon as I know), you must include "functions.js" first. Otherwise, "global.js" will not be able to find the calls. You can also make a little function inside "global.js" to include "functions.js" on the fly, like this:
function include(js_path){
//By Fabrício Magri e Micox
//http://elmicox.blogspot.com/2006/12/include-em-javascript.html
var new= document.createElement('script');
new.setAttribute('type', 'text/javascript');
new.setAttribute('src', js_path);
document.getElementsByTagName('head')[0].appendChild(new);
}
Than, on the beginning of your "global.js" you call this function to include the contents of "functions.js" on the section as soon as the browser requests "global.js"

Javascript Modular Layout : How to call a function defined in one module from another?

Below is an example of a modular layout of a javascript application. I want to start using such a structure for my work. I am struggling to get my head round how it works and need to understand how to call a function that is defined in one module from a different module? Is this definitely the bet way to layout a JavaScript heavy application?
window.MainModule = (function($, win, doc, undefined) {
var modules = {};
// -- Create as many modules as you need ...
modules["alerter"] = (function(){
var someFunction = function(){ alert('I alert first'); };
return {
init: someFunction
};
}());
modules["alerter2"] = (function(){
var someFunction = function(){ alert('I alert second'); };
return {
init: someFunction
};
}());
return {
init: function(){
for (var key in modules){
modules[key].init();
}
}
};
}(jQuery, this, document));
$(window.MainModule.init);
Modularity with RequireJS:
module1.js
define( ["dependency"] , function( dep ){
return {
speak: function(){
alert( dep.message );
}
}
} );
dependency.js
define( {
message: "Hello world!"
} );
impl.js
if ( $(".someCssExpression").length ) {
require( [ "module1" ] , function( mod ){
mod.speak();
});
}
index.html
...
<script src="require.js" data-main="impl"></script>
...
Your file structure will be modular.
Your implementation will be modular.
And no clunky namespacing or weird constructs to make it feel organised.
Takes some getting used to, but totally worth it.
Also read:
ScriptJunkie article
In order to access anything it needs to be available in the scope from where you are calling. "Module" - or any capsulation method for that matter - in JS always means "function". A module is just an anonymous (unnamed) function. So to access an element defined in another function B(module) from inside function A it either has to be made available in GLOBAL SCOPE (in browsers: the window object), OR it must have obtained access some other way, e.g. by having received a reference through some function call. YUI3 ([http://developer.yahoo.com/yui/3/]) is an interesting example for the latter, there nothing of your application ever is available in global scope (I consider YUI3 one of the by far best JS frameworks for SERIOUS softwarfe development, also definitely DO check out http://developer.yahoo.com/yui/theater/, especially any videos from Douglas Crockford, a Javascript God (and I'm not usually given to giving these kinds of statements).
What you have to keep in mind with Javascript is that part of what in languages such as C is done by the compiler now happens at runtime. For such things like immediate function invocations that return a function (causing encapsulation through usage of closures) you should remember that that code runs exactly ONCE DURING LOADING, but during runtime completely different code is executed - which depends on what the on-load code execution did.
In your example the function after window.MainModule=... is executed on loading of the JS code. Note that window.MainModule does NOT POINT TO THAT FUNCTION!!!
Instead, that function is, as I said, executed on load, and the RESULT is assigned to window.MainModule. What is the result? Well, there is just one return statement, and it returns and object, and the object has just one property "init" which points to an anonymous function.
Before returning that object, though, that function creates a variable "modules" in its local scope, which points to an object. The object has two properties, and those properties are assigned functions the same way that window.MainModule is assigned one, so you have three closures all in all.
So after loading you have one global variable
window.MainModule = {
init: function(){...}
So after loading you have one global variable
window.MainModule = {
init: function(){...}
}
In the last line that function is executed.
}
In the last line that function is executed.
The example does not make a lot of sense though, because you don't really encapsulate anything. You make available the private function with double pointers: from init to the local variable someFunction, nothing is hidden. Check out the above URLs (Yahoo Developer Theater) for better examples and very thorough explanations. It is MUST-WATCH even if you never touch YUI3 - especially the videos from D. Crockford are general JS knowhow.
Well umm..
It all depands on what you need from your application.
I would suggest sticking to the jQuery plugins for as long as you touch the gui.
You could use the Namespace pattern like yahoo, and just forge a great framework for your
application.
You probably don't need your modules to run on every page, like you did when instantiating the main module (There is no point to it unless f.e. you have a widget in every page on your website).
After you finish to abstract all the actions you need from your javascript into function and modules, build a module that will load the logic according to each page/action/whatever whenever you need it.
By the way, You can always develop OO style using mootools and this is endless really. It all boils down to your application needs
I would really recommend you to watch some lectures of Douglas Crockford(As been stated before me) and here is a nice article about modules that may help you understand it a bit further. Good luck!

Categories

Resources