What is this code in Javascript? - javascript

On some JS code on some sites I see Javascript code such as this:
SomeName.init = (function () {
// some stuff
})();
I mean, this is not a jQuery plugin code such as this:
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
Then, what is it? and what is the resulting JS object?

It's a anonymous function, which doesn't leak variables to the global scope when declaring variables using var.
SomeName.init = (function () {
return 3.1415;
})();
SomeName.init is a number (3.1415), because () after the anonymous function declaration executes the function. There's no way to obtain the original function, unless defined within the anonymous function:
(function foo(){
//foo refers to this function
too = foo;
})();;
//foo is undefined
//too refers to the function, because `too` has been defined without var

The Module Pattern. And those two snippets have more in common than you think.

(function () {
// some stuff
})()
is a anonymous function that calls itself instantly. It's just a closure around the code inside to stop the variable scope becoming global.

Whatever the function returns.
(function() {
//...
})();
Is used as a way to namespace code, or declare self-executing constructors. The resulting object is whatever that self-executing function returns.
The second snippet doesn't return anything and there is no resulting JS object.

Related

How to override this function in Javascript

I've got the following Javascript situation:
// First file - the one that I can't edit
(function(){
"use strict";
function test() {
alert("a");
}
test();
})();
This is defined in a Javascript file which I cannot edit. How would I go about overriding the test() method?
Redefining the function doesn't work. The output is still "a".
// My file - trying to override the first file's test() function
(function(){
function test() {
alert("b");
}
})();
Do you have any other suggestions?
In my mind the test() method must be defined somewhere, right? And if it is defined, I can override it.
Assign the function to a variable to create locally scoped functions that will behave the same within it's own function scope.
A scoped variable has priority over a global variable. So if you define a local variable in your own function you're overriding the other defined one. within the scope you're working in of course. On the outside of your scope the global object still persists.
You can't override a function in another scope. That is why a scoped function is scoped. It will keep a reference to it's local scoped variable. That's why the scopes are generally used, so you can encapsulate and protect your code to assure your code keeps working as intended.
unless it's a publicly exposed method, you can't override it.
(function(){
var test = function() {
alert("b");
}
})();
(function(){
"use strict";
function test() {
console.log("a");
}
test();
})();
(function(){
var test = function() {
console.log("b");
}
test();
})();
The text of the file can be edited if file is requested using XMLHttpRequest or fetch, then set edited response text to .textContent of script element, append script element to document.

Another variable trying to get outside of a function

I have some functions inside of functions and I am having trouble retrieving a variable. It will be easier to show in code I want to log the var three in the testit function but not sure how to do so.
test();
function test(){
var abc;
function one(){
abc = 1;
two();
}
var three;
function two(){
console.log(abc);
three = 2;
testit();
}
one();
}
function testit(){
console.log(three);
two();
}
to make test an object you would do the following:
function test(){
this.abc = 0;
this.three = 0;
this.one();
}
test.prototype.one = function(){
this.abc = 1;
this.two();
}
test.prototype.two = function(){
console.log(this.abc);
this.three = 2;
}
test.prototype.testit = function(){
console.log(this.three);
this.two();
}
and run it like so:
testObj = new test();
testObj.testit();
hope this helps.
edit: BTW: if you put a call in function 'two' back to function 'testit' you'll end up with an infinite loop.
Here's an explanation of what's happening:
When you wrap code in a function, you get what's called function scope. This means that the scope within the function belongs to the function and not to a scope above or outside of it (whichever way you want to look at it).
A closure allows an expression (typically, a function, as MDN states) to have it's own scope while sharing the scope of it's outer or higher scope.
So, let's look at an example:
// This represents the global, or window, scope.
// Analogous to window.outer_var.
var outer_var = 'outer var';
function outer_func() {
// New scope! Local only to outer_func and those
// expressions (functions) *enclosed* by
// `outer_func(){...}, e.g. inner_func(){...}.
var inner_var = 'inner var';
// Only outer_func() or inner-enclosed (to
// inner_func()'s definition) functions can
// access inner_func().
function inner_func() {
// Another new scope! Can access inner_var
// and inner_func_var (below). outer_func()
// canNOT access inner_func_var, though.
var inner_func_var = 'inner func var';
}
}
outer_func(); // Of course, it's in scope and accessible.
inner_func(); // This will cause ReferenceError: inner_func is not defined error.
Simply as it is (no wrapping context, with a closure), var outer_var is created with the global or window scope. It may be accessed in all of the following:
console(window.outer_var);
function outer_func() {console.log(outer_var);}
function inner_func() {console.log(outer_var);} No matter where inner_func's defined.
Here, #2/3 are analogous to:
function outer_func() {console.log(window.outer_var);}
function inner_func() {console.log(window.outer_var);}
Or global this:
function outer_func() {console.log(this.outer_var);}
function inner_func() {console.log(this.outer_var);}
Now, inner_var is accessible from the following:
function outer_func() {console.log(inner_var);}
function inner_func() {console.log(outer_var);} Only from within outer_func().
inner_func() may also only be accessed within outer_func(), because it belongs to the outer_func() scope, and thus is not visible/accessible outside of outer_func()*.
Lastly, inner_func_var is only accessible by:
function inner_func() {console.log(inner_func_var);} Only within outer_func().
To access your three variable, you have three choices:
Make three globally accessible (globals are generally discouraged as they may easily introduce difficult to resolve bugs when one is overwritten by some other code).
Return three from your test() function. In this case the value is accessed, not the actual variable within the function.
Create a property as #logic8 demonstrates, so it may be accessed as a property of an object.
* This isn't entirely true. outer_func() could export a reference to the function out of scope with return inner_func;. This is a more advanced concept, though, and won't be addressed here in depth. Here is an example.
You have to put it in a global to do so:
test();
var three = false;
function test(){
[..]
}
function testit(){
console.log(three);
two();
}
when you declare a variable with var it becomes local to that scope. If you want to access three in both functions, you can either declare it without var (making it global - generally frowned upon for good reasons) or declare it outside of the two functions: var three;
The correct way to do this is by using the closure pattern in javascript. This wraps your javascript class in its own function so anything you declare within that file is only local to your code.
Using jQuery, this is easily accomplished like so:
(function($){
//your code goes here
})(jQuery);
People typically do it this way so their javascript only executes when the page is ready:
$(document).ready(function(){
//your code goes here
});
It's a bit more complicated without jQuery if you want to execute your code when the document is ready:
document.addEventListener('DOMContentLoaded', function(){
console.log('document is ready. I can sleep now');
});
With your code, it would look something like this:
$(document).ready(function(){
var test = function(){
//test code here
};
var one = function(){
//one code here
};
var two = function(){
//two code here
};
var three = function(){
//three code here
};
var testIt = function(){
//test code here
};
});
This way, you can safely access all of your functions from the others without polluting the global namespace.

Why is a named function inside an "Immediately Invoked Function Expression" undefined when invoked from HTML?

I had this code:
Javascript
(function() {
function read() {...}
})();
HTML
<body onload="read()">
Console said, read is undefined.
After deleting the IIFE it worked, why?
Thanks. :)
Here's a long but satisfying explanation about JavaScript scope and closures.
Since you declare read inside a function, it is local to that function.
Anything you declare inside a function will be local to it.
You can explicitly put it into global scope by assigning it as a property to window:
(function() {
function read() {...}
window.read = read;
})();
Writing
(function() {
function read() { ... }
})();
Is very nearly the same thing as writing
(function() {
var read = function() { ... } //this is different, but not significantly so
//for purposes of teaching this point
})();
and I think you should already understand why a var declared inside a function is not available outside of that function's scope.
The behavior of a function definition (function read() { ... }) is slightly different from the behavior of assigning a function expression to a variable (var read = function() { ... };) in terms of when the name of the function and the function become associated, but the two are otherwise identical.
Because it isn't defined globally. It's only been defined within the scope of that immediately invoked function. To make it global either use this:
function read() {...}
(function() {
...
})();
Or this:
(function() {
window.read = function() {...}
})();
Or better yet, just bind the onload event within the immediately invoked function:
(function() {
function read() {...}
window.onload = read;
})();
In this case the definition of read is inside the IIFE. This limits the scope of the function to the IIFE and any child functions inside of it. The handler for onload is executed in the global scope and hence doesn't have access to read

Reuse function without global variables?

A couple of days ago I have learned on my own example how bad global variables and functions are. So apparently the best solution is NOT to use them, however sooner or later I will need to reuse my variables and functions over and over again.
So my question is: Can I reuse my functions and variables without declaring them globally? Can it be done?
For example, I want to reuse my alertBox function and my containsP variable couple of times:
DEMO: http://jsfiddle.net/ajmyZ/
//I am BAD GLOBAL FUNCTION inside var
//But I am reusable!!!
var alertBox = function () {
alert("Hey I am BAD function!!")
}
$(document).ready(function () {
//I am BAD GLOBAL var
//But I am reusable TOO!!!
var containsP = $("div p:first");
containsP.click(function () {
alert("Hi BAD var HERE!!");
});
$("p").eq(1).click(function () {
alertBox();
});
//I am the NICEST function here
//but I am NOT reusable :(
$("p").eq(2).click(function () {
alert("I am the NICEST function here!!");
});
});
I guess the simplest way to avoid clobbering the global object is just to create your own "application context". You can do that, by creating a self-invoking function which wraps your whole js-code within each file.
(function( win ) {
"use strict";
var still_global_but_only_in_this_anonymous_closure = true;
$(document).ready(function() {
// ...
// accessing the global object:
win.some_global_property = true;
});
}( this ));
Actually, you're already creating such a local context with your anonymous function you pass into .ready(). This is just the more explicit way. That self-invoking method, just calls itself with the global object as argument (where you still can explicitly access global variables). Furthermore, by invoking "use strict"; you're protected from accidently creating global variables alá "Ops_I_Forgot_The_Var_Statment = true;
The code you posted has no global variables. A variable declared inside of a function (in the case of your example, the anonymous document.ready handler) will never be global unless you make one of two mistakes:
forget the var keyword, making an implicit global
explicitly say window.myVar = ...;

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

Categories

Resources