IIFE jquery ready - javascript

I am working on a web project that has a large amount of javascript and we started hitting namespace collisions because we were adding everything to "$.".
I read up about namespacing and found the great article at http://addyosmani.com/blog/essential-js-namespacing/
I tried to set up the namespace inside of an IIFE as recommended and thought I was in luck because the function was already setup as
(function() { ... });
so I converted it to:
(function(namespace, undefined) { ... })(window.stuff = window.stuff || {});
only to find (after hours of work) that actually the original was
$(function() { ... }
Which means it was all being called in jQuery's ready() function.
I would like to keep the namespacing IIFE but cannot figure out how I would use it within jQuery's ready() function. Is this possible and if so how?

var namespace = (function() {
// local variables and functions
function readyHandler($) {
// DOM ready code
$("selector").method();
}
// exposed methods
return {
readyHandler: readyHandler
};
})();
jQuery(namespace.readyHandler);

Mmm, not sure if you got the concepts straight... None of those functions looks like an Immediately Invoked Function Expression because you're not invoking the function.
(function() { ... } ());
--^-- invoke function
jQuery's ready already creates a new closure so you don't need an IIFE anyway.
In any case, when using jQuery you can namespace your plugin in the $ namespace with an object that way you don't pollute it.
$.myplugin = {
...
}

Related

Javascript Library Quickstart

I'm trying to build a Javascript library that will provide some functionality for a JQuery Plugin I'm putting together.
I got the following skeleton code from searching online although I'm not quite sure how it all works (I do know it's a closure). I've added my functions via declarations.
(function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
})(window, document, jQuery);
So I put the above code in a separate JS file and then source it in my HTML page, then I run try to run the function like so (Note: I have JQuery set up as well):
<script type="text/javascript">
$(document).ready(function() {
console.log(func_1());
});
</script>
However, I seem to be getting some errors in Firebug (ReferenceError: func_1 is not defined).
I have two questions:
How do I call my functions?!
I'd like to be able to call the functions in the following format: className.functionName(). How do I restructure the skeleton code to enable me do this and, say, call my function like this: Device.func_1()?
Thanks for your anticipated assistance.
The closure is used to hide internal functions from the rest of the code. You need to explicitly expose the public functions of the library:
var Device = (function(window, document, $) {
function func_1(){
return 1;
}
function func_2(){
return 2;
}
var internalDevice = {
func_1: func_1,
func_2: func_2
};
return internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
The (function(window, document, $) {})(window, document, jQuery); part is called an immediately invoked function expression (IIFE). It's used to avoid leaking all the library functions into the global scope. Otherwise, if some other library had a func_1 function it would either be overwritten or overwrite your library's func_1.
The arguments to the function are used to control how the library can affect other parts of the code and relies on it. For example, someone might overwrite the window.$ library so that $ is no longer available everywhere in the code. But since you have a local reference in the closure you can still access it.
Alternatively to using the code above - returning an object - you could also assign your library directly to the global scope:
(function(window, document, $) {
...
window.Device = internalDevice; // expose functionality to the rest of the code
})(window, document, jQuery);
I can only answer question number two, but you can create that by doing this:
var Device = {
function func_1()
{
// your first function
},
function func_2()
{
// your second function
}
};
That way you can just call:
Device.func_1();
Hop that helps :)
When something is inside a closure the scope of it is changed to that closure. func_1 and func_2 can only be seen inside the anonymous function calling them and below.

start javascript code with $(function, etc

I am studying Backbone and the todo example apps from http://todomvc.com/
I have noticed there are 3 severals ways of starting the code in the files:
$(function() {
// code here
});
$(function( $ ) {
// code here
});
(function() {
// code here
}());
I do not understand the differences and when I should use one over the other.
I also saw some people using this to start their code:
$(document).ready(function(){
// code here
});
From what I have seen, this is the full way of writing it right?
In a more general way, should I always include my javascript code into something like that in each files?
Thanks for your advice.
$(document).ready(function(){}) ensures that your code runs on DOM ready, so that you have access to the DOM. You can read more about this in jQuery's documentation.
$(function(){}) is just an alias to #1. Any code in here will wait for DOM ready (see the docs).
$(function($){}) is equivalent to #1 and #2, only you get a clean reference to jQuery in the local scope (see the note below). You can likewise pass in $ to the function in #1, and it'll do the same thing (create a local reference to jQuery).
(function(){}()) is just a self-executing-anonymous-function, used to create a new closure.
Please note that none of these are specific to Backbone. The first 3 are specific to jQuery, while #4 is just vanilla JavaScript.
Note: To understand what's going on in #3 above, remember that $ is an alias to jQuery. However, jQuery is not the only library that uses the $ variable. Since the $ might be overwritten by someone else, you want to ensure that within your scope, $ will always reference jQuery - hence the $ argument.
In the end, it basically boils down to the following 2 options:
If your JavaScript is loaded in the head, you have to wait for document ready, so use this:
jQuery(function($) {
// Your code goes here.
// Use the $ in peace...
});
If you load your JavaScript at the bottom of your document (before the closing body tag - which you should definitely be doing), then there's no need to wait for document ready (since the DOM is already constructed by the time the parser gets to your script), and a SEAF (A.K.A. IIFE) will suffice:
(function($) {
// Use the $ in peace...
}(jQuery));
P.S. For a good understanding of Closures and Scope, see JS101: A Brief Lesson on Scope.
I guess it makes sense to start out, by realizing that $ = jQuery. The purpose of which down below when reading about namespaces within anonymous functions will make more sense. But in essence, you can use either of them. One would use jQuery() instead of $() if they were using multiple libraries, and wanted the $ to be used by the other one.
$(document).ready(function(){
// Here we have jQuery(document) firing off the ready event
// which executes once the DOM has been created in
// order to ensure that elements you are trying to manipulate exist.
});
​$(function () {
// Short-hand version of $(document).ready(function () { });
});
More information on Document.ready()
Putting the $ within the parenthesis ensures the jQuery $ alias (you can be safe it always signifies jQuery this way).
$(function ($) { /* code here : $ always means jQuery now */ });
Lastly you have an IIFE (Immidiately-Invoked Function Expression)
- IIFE explanation
(function (myNameSpace, $) {
// This is an anonymous function - it is ran instantly
// Usually used for namespaces / etc
// This creates a scope/wrapper/closure around everything inside of it
}(window.myNameSpace, jQuery));
The $ at the top (with it's matching jQuery on the bottom) signify that the
$ (dollar sign) stands for jQuery within the scope of the namepsace.
This is done to ensure that other libraries do not collide with what the developer
intends/wants the $ to be used with.
(function (myNameSpace, $) {
// Now because of all of this scope/wrapper/closure awesome...
// you can create -INTERNAL- variables (sort of like Private variables from other langs)
// this variable cannot be accessed outside the namespace unless it is returned / exposed
var internalVariable = '123'; // Internal
// Even Internal functions!
function privateFunction () {
console.log('this is private!');
}
// --------------------------------------------------------
// Public -method- of nameSpace exposing a private variable
// Notice we're using the myNameSpace object we exposed at the top/bottom
myNameSpace.nameSpaceMethod = function () {
privateFunction(); // we can call the private function only inside of the namespace
return internalVariable; // now we could get this variable
};
}(window.myNameSpace, jQuery)); // notice these mirror the above arguments in the anon function
More information on anonymous functions
Now if we're outside of the namespace, we can see how these internal/public methods and variables are effected:
// This will come up undefined
alert(internalVariable);
// This will trigger a -method- of the myNameSpace namespace - and alert "123"
// Showcasing how we access a Public method - which itself has access to the internal variable
// and exposes it to us!
alert(myNameSpace.nameSpaceMethod());
​
These two:
$(function() {
// code here
});
$(document).ready(function(){
// code here
});
Are directly equivalent, they are both the way to start some jQuery when the document has loaded. The former is just a shorter version of the latter.
This one:
(function() {
// code here
}());
is just a scoped function with zero parameters, which is immediately called with zero parameters.

Accessing a function defined inside a function from the global scope?

Long story short, I have a long code that uses jQuery. Lots of files, functions, etc. A less than ideal amount of our users are having issues with our code because some addons, toolbars and the like they have installed breaks our JavaScript code because of jQuery gets included twice and nasty stuff like that.
I thought I could just
Include jQuery
Use $.noConflict
Then include the whole rest of my code between something like:
.
(function($) {
// All of my code goes here.
})(jQuery);
I haven't checked if this fixes our issues with those users, but it does work. The problem is, in one part of the site (image upload) we have an iframe that needs to call some of those functions defined in our big chunk of code. I've tried putting those functions out of this unnamed function call, but it uses, on itself, other functions which have to be there.
Any idea or workaround of how could I be able to access functions defined inside that function (shown above) from a code that's outside of it?
Thanks!
You cannot access a function context from the "outside world". Well, to be accorate you could do it in some older js engines which allowed for accessing .__parent__ attributes, but that is old'n'busted and no longer available.
However, you would need to either expose some functions within your closure, or you creating a namespace object where you write all of your logic in (which also has to be available in the parent context).
So I'd suggest something like
(function( $ ) {
function myFunc() {
// do stuff
}
function anotherFunc() {
}
window.myFunc = myFunc; // expose myFunc globally
}( jQuery ));
Maybe even better:
var myNameSpace = { };
(function( $ ) {
myNameSpace.myFunc = function() {
// do stuff
};
}( jQuery ));
// somewhere else
myNameSpace.myFunc();
It is not an ideal practice, but you can declare those functions in the global scope.
(function($) {
globalFunct = function (arg1, arg2) { // Don't use var keyword
...
};
})(jQuery);
It isn't ideal because you can run into naming collisions, much like you are observing with jQuery. Improve upon this approach by putting all of your globally-accessible methods in a "package." Choose a unique name for it. This will prevent collisions.
// Somewhere outside of your anonymous function, in the global scope
var myPackage = {};
(function($) {
myPackage.globalFunct = function (arg1, arg2) {
...
};
})(jQuery);
Then call that method by invoking myPackage.globalFunct().
Why are you wrapping your code in a call to the jQuery function object which you pass in to your self-executing anonymous function; are you meaning to create a jQuery object from all of your code?
In order to expose your code to the outside world, you need to assign your functions and objects to an object which is outside of the scope of your code, such as the window object.
For example, if you had created an object containing various methods and properties that you wanted to expose, you could do this:
//Your self-executing anonymous function
(function($)
{
//Object which contains various useful methods and properties
var useful = {...};
//Expose it to the outside world
window.Useful = useful;
})(jQuery);
EDIT: as others have noted, it is not an ideal solution as you will indeed run into naming collisions if you are not careful. Also, using an object external to your anonymous function as a namespacing object (as others have stated) is my preferred method
Yes, you can "export" the function from within a closure:
Yes, you can "export" the function from within a closure:
(function() {
function a() {
console.log("a");
}
function b() {
a();
console.log("b");
}
// make b globally available
window.b = b;
})();
b();
window.PARTY_CATS_jQuery = jQuery.noConflict(true);
(function($) {
$(function() {
// All of my code goes here.
});
})(COMPANY_NAME_jQuery);
Then just use PARTY_CATS_jQuery in your global functions
If you feel PARTY_CATS_ is not a unique enough name pick something safer like BABY_KILLER_jQuery

what does this construct do in javascript

i really tried to understand, what meaning the the following contruct has in JS, but i could not figure out:
how it works
why & in which situation this construct should be used?
Pls could someone can tell me? Thank you!
(function () {
...
}());
// Or in jQuery plugins i saw it very often
(function( $ ){
...
})( jQuery );
(function () {
...
}());
Defines a function. Calls it immediately. Doesn't store it anywhere.
Usually used to limit the scope of variables inside it.
(function( $ ){
...
})( jQuery );
Exactly the same, except it has an argument. Used so the unhelpfully non-descriptive variable $ can be used without having namespace conflicts with all the other libraries that thought $ was a good name for a variable.
This is called Closure and it's main point is to encapsulate your inner code in order not to mix it with a global scope.
Read this for more details
The second part
(function( $ ){
...
})( jQuery );
Is used to enable your code to use $ as a reference to the jQuery object, without it conflicting with other javascript libraries (like Prototype).
See the jQuery documentation:
http://docs.jquery.com/Using_jQuery_with_Other_Libraries#Referencing_Magic_-_Shortcuts_for_jQuery
These are closures. There is tons of information on this style of JavaScript programming but the gist of it is that its an immediately executing function. If you look closely at the syntax this makes perfect sense -
( ) causes an execution to take place.
//Function immediately executes.
(function() {
});
//Wait we can do better, let's pass in an argument
(function($) {
//$ is now a local variable inside this tightly scoped function
//So that I can describe this as a closure I've added members to this function
var foo = 0,
bar = function() {
return foo;
};
return {
foo: bar
};
}(jQuery));

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources