The Google Analytics tracking code looks like this:
(function() {
code
})();
What's the technique they are using with those brackets - (stuff)() - called? What does it do?
I put the Google Analytics code before the closing head tag on my page and then put an if statement around it like this (I include a Jquery cookie plugin further up):
<script type="application/javascript">
if ($.cookie('allowcookies') == 'yes') {
analytics code
}
</script>
It didn't run until I used the same technique around my code:
(function() {if ($.cookie('allowcookies') == 'yes') {
analytics code
}
})();
Why did it not run before I did that? Why did it run after?
(function() {
/* code */
}());
It's commonly known as «self executed anonymous function (¹)» (o «immediate function invocation») and its main use is to avoid the creation of variables into the global (or in the outer) scope.
It's also used as shortcut when you want to create a function to execute just once, without the need to first define the function with its own identifier and then soon make the function call.
It may be eventually used inside a scope and then it may create a closure if the outer context (or other references) are binded through parameters passing, e.g.
/* outer scope */
(function(outerscope) {
element.onsomeevent = function() {
/* do something with outerscope */
};
}(this));
Another practical use I make with this expression is when I need to create a function to be soon executed inside a constructor function when it is called with new keyword (instead of an explicit call to some init method).
(¹) — as stated on book "Mantainable Javascript" by Nicholas Zakas (O'Reilly, ISBN 978-1-449-32768-2) page 44, the suggested expression is (function() {}()), with nested parens (even if (function() {})() will work anyway)
[...]To make it obvious that immediate function invocation is taking place, put paretheses around the function[...]
See also Immediate function invocation syntax
The "function(){code}" part only creates a function, the () at the end call the created function.
You could rewrite
(function() {
code
})();
As
var x = function() {code};
x();
It's just a select calling function. The () at the end causes it to be called automatically.
It's used like this to isolate local variables that are relevant only to your code from the global scope.
For example:
(function() {
var x = 5;
window.y = 6;
})();
x is available only in the scope of the function, y is globally available through the window.
As to it not running, I'd hazard that's down to the conditional you supplied.
Related
I am creating a wrapper for some arbitrary code (let's call it managed code). The managed code may include some functions that are defined in the window scope and are expected by other scripts on the page (horrible, 1997, practices, I know, but such is what I have to deal with), as global functions.
The purpose of the wrapper is to delay executing the wrapped code until jQuery is loaded. It looks like this:
(function () {
var once = true,
check = setInterval(function () {
if (window.$ && once) {
once = false; // setInterval can stack up if the UI freezes. Ensure this only gets called once.
executeBundle();
clearInterval(check);
console.log('Jquery loaded');
}
}, 100);
})()
// Wrapper proper
function executeBundle() {
// oodles of code of any origin
}
Now that the managed code is wrapped inside the executeBundle function, all functions/variables declared within it will be scoped to that function. This isn't a problem for the managed code itself, but for other scripts that load separately that may rely on global functions it provides.
I'd like to know if anyone knows a strategy like eval, but without the security issues, that may allow me to preserve the window scope for the running of the managed code. The constraint is that I can't modify the managed code at all--just the wrapper.
Based on T.J. Crowder's phenomenal answer, I realized that I could add the managed code to a <script> element and add that to the <head> like this:
var codeBundle = // Code in one long string
function evaluateBundle() {
var script = $('<script type="text/javascript"/>')
script.html(codeBundle);
$('head').append(script);
}
And let the parser evaluate the code.
I'd like to know if anyone knows a strategy like eval, but without the security issues
If you're evaling code of your own that you would run by having it in a script tag anyway, there are no security issues. You're running code either way.
You can't do this if the code you're wrapping will appear directly within evaluateBundle and it has declarations (vars and function declarations) that were supposed to be at global scope. Handling those would require modifying the wrapped code.
You can do this if you load that code separately, though, and then do a global eval on it. For instance, put it in a script block with a non-JavaScript type so the browser doesn't execute it:
<script type="x-code-to-wrap"></script>
...and then:
function evaluateBundle() {
var code = document.querySelector('script[type="x-code-to-wrap"]').textContent;
(0, eval)(code);
}
(The (0, eval)(code) bit is the global eval, more on MDN).
You may have to adjust the textContent part of that for cross-browser compatibility. This question's answers suggest using jQuery's html function:
function evaluateBundle() {
(0, eval)($('script[type="x-code-to-wrap"]').html());
}
Live example on JSBin
I am trying to create namespaces in JavaScript as in the following script:
var hlAdmin = hlAdmin || {};
hlAdmin.editCompany = function (src) {
// function script
}
Then I call the function in HTML:
onclick="hlAdmin.editCompany(123)"
I get a reference error: Cannot find "editCompany".
Anyone know why?
Based on your comments I assume the following:
The equivalent script (and scoping is like):
<html><head>
</script>
var hlAdmin = hlAdmin || {};
hlAdmin.editCompany = function (src) {
// error in this script
}
</script>
</head></body>
<button onclick="hlAdmin.editCompany(123)">Caption</button>
</body></html>
In this example hlAdmin is indeed in the global scope (the root-scope of the host, called window in browsers).
If (in this example) you get reference error: Cannot find "editCompany", then one should look at other error-messages in your (browser's) error-log, because when there is a fatal error in the function for hlAdmin.editCompany, then that function will not be created (hence .editCompany becomes a property that points to undefined instead of a method that points to the function OR .editCompany doesn't even exist (depending on engine/error)).
To investigate if you indeed have a scoping-problem you could test this by: window['hlAdmin'] || (window['hlAdmin']={}); (or some equivalent variant). If that made the code work, then it seems you have some scoping-problem.
Hope these steps help someone in the future.
It's generally considered bad form to mix inline javascript and non-inline. The preferred way to do this would be to keep all the javascript in one place using an event handler:
window.hlAdmin = window.hlAdmin || {};
window.hlAdmin.editCompany = function (src) {
// function script
}
document.getElementById('yourElementId').onclick = function() {
hlAdmin.editCompany(123);
};
To more specifically address the issue: One thing that could cause this issue is if the hlAdmin object is not ending up in the global scope. You stated that this declaration is "at the top of the JavaScript file", but if it's in any kind of function (such as a function set to window.onload, or the jQuery $(function() { ... });) it would not end up in the global scope when declared as a var. A variable declared with var will only end up globally scoped if it's in the root scope, outside of any kind of function. If rather than using var hlAdmin you instead use window.hlAdmin, this will make sure that even if you're inside a document ready function or something similar, you're creating your hlAdmin in the global context, which will fix the problem if it is in fact an issue of scope.
I found the problem.
The browsers (at least Aurora and Chrome) are dropping the namespace in the onclick attribute. When you look at the browser html the namespace has just disappeared from the markup.
A simple question.
I have a web project includes multi JavaScripts.
JS:
// (1) Event
$('.input').keyup(function()
{
keyUpFunction();
});
// (2) Function
function keyUpFunction(){ ... }
(1),(2) which should come first in one javascript file? If the browser read the function first, does it store the function in memory and invoke it when scan the event.
In some case, the same function is defined in multi javascript . e.g.
prm.add_endRequest(function() {
fn1();
fn2();
});
$(document).ready(.......)
Should I duplicate the function name and define each component in each js file.
or keep the function declare in one file and invoke sub-function composite the function?
Functions defined in the following manner:
function fooBar(){}
Are 'hoisted' to the top of the current scope. This means they will always be available, in the current scope, even if they are defined at the end of the file.
This does not hold true if you defined you functions like this:
var fooBar = function(){};
These functions are not hoisted, and must be defined before they can be used.
It should be noted that in your specific example, keyUpFunction will only be called once a keyup event has fired. This also means that all javascript on your page will already be evaluated, so the keyUpFunction will be defined (parsed) already regardless.
EDIT: To be more explicit, this first example is okay:
doSomething('hello world');
function doSomething(str){
console.log(str);
}
However, this will cause you problems:
doSomething('hello world');
var doSomething = function(str){
console.log(str);
}
#Matt's answer covers the function hoisting stuff nicely.
To avoid function name clashes within multiple files, wrap your content in an immediately invoked function expression, e.g.:
(function() {
// put your variables functions here
...
// register event handlers
})();
Any variables or functions declared therein will be constrained to that 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
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.