I'm not sure which JavaScript design pattern I'm following. Can someone please help shed some light on it?
var masonrySupport = ({
large__videos__support: function() {
$('.masonry-container .largeRec').find('.itemMasVideo').parent().addClass('item_largeRec_video_height');
},
smallRec__videos__support: function() {
$('.masonry-container .smallRec').find('.itemMasVideo').parent().addClass('item_smallRec_video_height');
},
init: function() {
this.large__videos__support(),
this.smallRec__videos__support()
}
})
masonrySupport.init();
There are two "patterns" I can see here.
Using self invoking closure to isolate scope.
(function($) {
// Code here
})(jQuery);
Helps mitigate the creation of accidental global variables.
(Kind) the module pattern, where you create an object with a bunch of methods on it, and call init(). I prefer to self invoking closure version of it. The Revealing Module Pattern.
The pattern you are using is called the Module Pattern, and it is one of the most important patterns in JavaScript. You outer wrapper creates an anonymous scope that provides privacy and state to the code that you place inside it.
(function($) {
// Everything in here is private and stateful
// and we can access jQuery through the imported $ variable
})(jQuery);
To your scope, you're also passing the global jQuery object. This method is called global import, and is faster and clearer than accessing the implied global from within your scope.
Inside your scope, you are creating an API that is accessible through the masonrySupport variable, making it a Revealing Module Pattern.
I don't see this as a design pattern in the strict sense of terminology. May be associated with the module pattern, but it needs to return something to be accessible outside of it's inner scope. It's only a self executing function invoked inside a scope which in this case is jQuery. This is used in many jquery plugins. You isolate the scope of the self executing function to a specific - lets say - domain.
This can be found on the first declaration:
(function($) {
...
})(jQuery);
By closuring the function you are guarding the functions and variables declared inside the scope to a specific domain, in this way eliminating the possibility to accidentally override or redeclare some function or variable declared in the global scope. It's a common practice to isolate the scope from the global object which in Javascript world is the Object or on DOM context is window.
And it continues with the self executing function:
$(function() {
...
})
Effectively what is being done here is, once the document loads, execute two functions - 'large__videos__support' and 'smallRec__videos__support.'
Let's understand how it is being achieved,
Firstly it is Immediately-Invoked Function Expression (IIFE) in action. This pattern is often used when trying to avoid polluting the global namespace, because all the variables used in the function are not visible outside its scope.
(function($) {
...
})(jQuery);
Short hand of $( document ).ready() is being used. More here.
$(function() {
...
});
Thirdly, you are initializing one object being referenced by 'masonrySupport' and calling its method 'init.'
In JS, this is called and Immediately Invoked Function Expression (IIFE), and is known as the module pattern.
However in jQuery this pattern is used to create jQuery Plugins. I advise you to follow the best practices to make it work.
Check that jsfiddle to get you started.
Below the JS part:
(function( $ ) {
$.fn.masonrySupport = function( option ) {
if ( option === "large") {
this.find('div.itemMasVideo').parent().addClass('item_largeRec_video_height');
}
if ( option === "small" ) {
this.find('div.itemMasVideo').parent().addClass('item_smallRec_video_height');
}
return this;
};
}( jQuery ));
$( 'div.masonry-container.largeRec' ).masonrySupport( "large" );
Related
I'm having some issues with running some functions from an external js file.
The html includes:
<script src="js/file.js"></script>
<script>
$("#center-button").click(function() {
explodePage("center");
});
</script>
The js file includes:
var explodePage = function(button) {
//code here
aboutPage();
}
var aboutPage = function() {
//code here
}
The explodePage function runs fine, but as soon as it reaches the call to the nested aboutPage function, it starts throwing these uncaught typeerrors at me. It works fine if I don't use an external js file and just put everything into the html. Pretty new to this so probably missing something obvious in scope or something. Any solutions?
Declare the function's definition as below:
function explodePage(button) {
//code here
aboutPage();
}
function aboutPage() {
//code here
}
Explanation:
When you use the var keyword for declaring functions, the execution of JS happens as when the variable is initialized, you cannot reference or use variable's before declaration. In contrast with the name function defintion JS interpreter first picks the enclosed functions before execution and initializes it before the code execution. This is called AST- Abstract syntax tree that is followed by JS interpreters.
Also Remember:
Also bind your Jquery code inside a Jquery document ready function, just to make sure the Jquery and the DOM elements are available for the bindings.
It's not a good a idea to pollute the global window object with variables, since there can be collisions. And immediately-invoked function expression is a good solution for this.
(function(){
//You can declare your functions in here, and invoke them below
$( document ).ready(function() {
//Check that the DOM is ready, in order to manipulate it an add events
$("#center-button").click(function() {
explodePage("center");
});
});
})($); //Notice that we are injecting a dependency, in this case jQuery
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
I'm refactoring about 600 lines of javascript into the module pattern. Here is a start from previous post:
I undertand the concept of anonymous methods...and sefl-executing....but not the scoping concepts...i.e. what global and window do.
window.onload=initialize_page;
(function (global) {
global['test'] = 'test';
function initialize_page()
{
/* fill here */
}
})(window);
Can I put window.onload=initialize_page into my module pattern? Or does it need to be put outside of it? Can someone explain how the access works?
EDIT 1: per Answer
(function () {
addEventListener('load', initialize_page);
function initialize_page()
{
alert ("hi");
}
})();
It is a global. Don't touch it like that, you'll overwrite any other code that tries to assign load handlers.
Use addEventListener (or attachEvent for old IE) instead. There are plenty of libraries that abstract the functionality.
I'm not an expert, but I think window.onload is a function that gets called, so you reset it to be another function (that you created). You're using it as a macro there. Since initialize_page does not exist when you passed it, it will probably get passed to window.onload as null.
I have an external JavaScript file that will be used on pages with lots of other scripts. My script involves a lot of jQuery that listens for events, and by design, I have many global vars declared. I've been reading best practice articles, and a lot is said about 'polluting the global namespace' and inadvertent script interaction.
What's the best way to enclose (encapsulate?) my JavaScript file so that:
I can still access some of the
variables outside of the enclosure
The jQuery event listeners will
function properly
I'm not at liberty to disclose the code, so even general responses are appreciated. Additionally, any other tips on making scripts less vulnerable to other scripts on the page are welcome.
I've found enclosure styles for regular JavaScript, but does the use of jQuery complicate this?
Generally what this boils down to is encapsulating your objects into a "namespace". I use quotes there because the term is not an official semantic in JavaScript, but rather one that is achieved through basic object encapsulation.
There are several ways to do this, and it ultimately comes down to personal preference.
One approach is to just use a basic JS object, and keep everything in it. The name of the object should be semantic and give the object some meaning, but otherwise it's purpose is to just wrap your own code and keep it out of the global namespace.
var SomeName = {
alpha: 1,
beta: {a: 1, b: 2},
gamma: function(){
SomeName.alpha += 1;
}
}
In this case, only SomeName is in the global namespace. The one downside to this approach is that everything inside the namespace is public, and you have to use the full namespace to reference an object, instead of using 'this' - e.g. in SomeName.gamma we have to use SomeName.alpha to reference the contents of alpha.
Another approach is to make your namespace a function with properties. The nice feature of this approach is you can create 'private' variable through closures. It also gives you access to closured functions and variables without full namespace referencing.
var SomeName = (function(){
var self = this;
var privateVar = 1;
var privateFunc = function() { };
this.publicVar = 2;
this.publicFunc = function(){
console.log(privateVar);
console.log(this.publicVar); // if called via SomeName.publicFunc
setTimeout(function(){
console.log(self.publicVar);
console.log(privateVar);
}, 1000);
};
}();
The other bonus of this approach is it lets you protect the global variables you want to use. For example, if you use jQuery, AND another library that creates a $ variable, you can always insure you are referencing jQuery when using $ by this approach:
var SomeName = (function($){
console.log($('div'));
})(jQuery);
One method is to namespace like this:
var MyNamespace = {
doSomething: function() {},
reactToEvent: function() {},
counter: 0
}
You will just have to refer to the functions or variable using the namespace: MyNamespace.reactToEvent. This works fine for separating what you would normally have in the window (where all the confrontation is).
You can wrap your code in an anonymous Javascript function and only return what you want to expose to the outside world. You will need to prefix var to your global variables so that they remain only in the scope of the anonymous function. Something like this:
var myStuff = (function() {
var globalVar1;
var globalVar2;
var privateVar1;
function myFunction() {
...
}
function myPrivateFunction() {
...
}
return {
var1: globalVar1,
var2: globalVar2,
myFunction: myFunction
};
})();
Now you can access myStuff.var1 and myStuff.myFunction().
Two ways to encapsulate or limit namespace pollution
1) Create one global var and stuff everything you need into it.
var g = {};
g.somevar = "val";
g.someothervar = "val2";
g.method1 = function()
{
// muck with somevar
g.somevar = "something else";
};
2) For inline scripts, consider limiting the scope of the functions called.
<script>
(
function(window)
{
// do stuff with g.somevar
if(g.somevar=="secret base")
g.docrazystuff();
}
)(); // call function(window) then allow function(window) to be GC'd as it's out of scope now
</script>
I just started using RequireJS and have now become obsessed with it.
It's basically a dependency management system in a modular JavaScript format. By doing so you can virtually eliminate attaching anything to the global namespace.
What's nice is that you only reference one script on your page require.js then tell it what script to run first. From there it is all magic...
Here's an example implementation script:
require([
//dependencies
'lib/jquery-1.6.1'
], function($) {
//You'll get access to jQuery locally rather than globally via $
});
Read through the RequireJS API and see if this is right for you. I'm writing all my scripts like this now. It's great because at the top of each script you know exactly what you dependencies are similar to server-side languages - Java or C#.
This is a common practice with jQuery plugins for the same reasons you mention:
;(function ($) {
/* ... your code comes here ... */
})(jQuery);
This is an immediate function. If you declare your "global" variables inside, they will be local to this closure (still "global" for the code you create inside). Your event listeners will work inside here too, and you will still be able to reach real global variables.
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));