Self-executing anonymous functions and closures - javascript

information
I am trying to build a site where I can include certain files and append to my global variable with different methods that will just add easily to the object. Meaning I only need to include the file and this page will now have access to everything in the hutber object.
core hutber.js
var hutber = {};
(function ($) {
"use strict"; //For good development standards :)
hutber.init = function(){
};
hutber.init();
})(jQuery);
extra bits hutber.form.js
(function ($) {
"use strict"; //For good development standards :)
hutber.form = {
}
});
problem
I am aware that the hutber will not have access to hutber.form as it within a closure. So without taking these out of selfexecuting functions how can I get hutber to have access to hutber.form?
Or is this just the complete wrong way to approach this?

No it will have access to hutber.form since hutber is global, but the problem is timing.
If the init() runs before the hutber.form function is executed, it will not be there. The init can not run to all of the "add-ons" are loaded.
A side note: your second one will not run since it has no (jQuery);.
(function ($) {
"use strict"; //For good development standards :)
hutber.form = {
}
}); <-- missing (jQuery); so it is not going to do anything
Run a little demo to see what happens.
var myObj = {};
(function(){
myObj.init = function(){
alert("init");
try{ //will fail since bar has not loaded yet
myObj.bar();
} catch(e){ alert("failed calling bar"); }
};
//call init before bar is loaded
myObj.init();
})();
(function(){
myObj.bar = function(){
alert("bar");
};
})();
//call init after bar has been loaded
myObj.init();
jsFiddle of above code
When you run this, you will see that the init will fail the first time it is called since bar is not loaded. The second time it will work since the method is added. So if the init depends on the loaded "modules" it needs to know when they are loaded in order to call the init method.

I think you want this:
<script src="hutber.js"></script>
<script src="hutber.form.js"></script>
<script> hutber.init(); </script>

Seeing as how you defined hutber as a global variable the "form" property will certainly be accessible within any immediately invoked function expression.

You might be looking at this the wrong way.
Not to say that immediately-invoked functions are the wrong way to build functionality...
What I am saying, however, is that you've got a globally-available object, which you're referencing directly from within your function...
After you assign hutber.form = {};, everything in whole world of the global scope has full access to hutber.form, because hutber is globally-accessible.
It really wouldn't be any different than if you went like:
//form.js
hutber = hutber || {};
hutber.form = { /* ... */ };
In terms of public access to hutber.form.
The closure covers the things you DON'T return and the things that you DON'T assign to objects/arrays/vars in an outer-scope.
So if you had var mySecretIdentity = "Jerry O'Connell"; inside of the closure, then only the methods inside of hutber.form could access mySecretItentity...
...but again, you could accomplish the same by doing something like:
// form.js
hutber = hutber || {};
hutber.form = (function () {
var mySecretIdentity = "Jerry O'Connell";
return {
submit : function () {},
clear : function () {},
validate : function () {}
};
}());
And now anything private can only be directly-accessed by the functions which were written inside of the closure.
So again, it comes down to: "What problem are you trying to solve?"

The <script> tag order is important as #Sime Vidas mentioned.
Do the following order:
<script src="hutber.js"></script>
<script src="hutber.form.js"></script>
I modified the script in jsFiddle. You'll note that I like being explicit about global variables by using window.variable. I have the init function in the core hutber.js file firing immediately, if that's what you want.
//core hutber.js
window.hutber = {}; // Explicit Global Variable
(function ($) {
"use strict"; //For good development standards :)
window.hutber.init = function(){
alert('init fired');
};
window.hutber.init(); // You can fire this anywhere since you set it on a global variable...
})(jQuery);
//Extra bits hutber.form.js
(function ($) {
"use strict"; //For good development standards :)
window.hutber.form = {prop: "hello im a form"}
alert('window.hutber.form is now' + window.hutber.form.prop);
})(jQuery);

Related

Running a jquery function from JS

Sorry for the noobish question, but nothing works for me today.
I'm creating a Phonegap application and have intergrated PushWoosh API into my app. And on receive push notification I want to run my previous functions again, so the data will be updated.
Pushwoosh has JS function like this:
document.addEventListener('push-notification',
function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
var notification = event.notification;
if (typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
var object = JSON.parse(notification.u);
window.runPushFunctions(object.active, object.open); //Runs a jQuery function I have created..
}
);
Now window.runPushFunctions looks like this:
$(document).ready(function() {
window.runPushFunctions = function(active, open) {
if (active != null || active != undefined) {
$('.hubs-page').removeClass('hubs-active').hide().eq(active).show().addClass('hubs-active');
}
if (open == 2) {
$('html').addClass('hubs-opening');
}
//Trying to run functions from jQuery file that will get data from database and so on..
received();
sent();
checkFriends();
};
});
But I can't for some reason not run received(), sent(), checkFriends().
These functions is set like this in their own files like this:
(function($) {
'use strict';
function checkFriends () {
$.getJSON('url',function(data){
$.each(data,function(index,value){
//Do something with value
});
});
}
Im including files in this order:
file.js -> received(); sent();
file.js -> checkFriends();
file.js -> pushnotifications
Any help will be gladly appreciated
As the other answer here says, you are scoping your method definitions so they are not accessible anywhere outside the containing method.
(function($) {
This is a method definition. Any variables or functions non-globally declared within it cannot be accessed outside it. Therefore, you need to define the functions somewhere else or make them global for them to be accessible.
If you go for defining them somewhere else, you can simply move the function definitions to the top of the same file, outside of the (function($) {})() scope.
If you go for global definitions instead, you need to change the methods' defining lines slightly: instead of
function foo() { }
you need
window.foo = function() { }
This assigns an anonymously declared function to an object in the window scope, which is globally accessible. You can then call it using
window.foo();
or simply
foo();
since it is in the window scope.
I'm not exactly sure I'm understanding your question, but it looks to me like you are defining the function checkFriends inside of a function scope. If you need access to that function definition, you would need to declare it on an object that can be referenced from the global scope. Obviously the easiest way to do that would be to attach it to the window, though there are plenty of reasons not to do that.
window.checkFriends = function(){//code that does stuff};

How do I make functions added by Tampermonkey be available in console after the script has been ran?

I made a script that among other things has a function in it:
function updateGUI(){
document.getElementById("cursoft").value = getSoftware();
document.getElementById("curver").value = getCurrentVersion();
document.getElementById("rcycles").value = getResearchCycles();
document.getElementById("rcycle").value = getCurrentCycle();
document.getElementById("curproc").value = getCurrentProcess();
document.getElementById("curact").value = getCurrentAction();
}
The script runs on page load just fine, but when I try to run this function after the script finishes execution it's "undefined".
How can I make it "stay" in the current scope?
Tampermonkey scripts are run in a separate scope. This means that to make a function available globally you'll want to do something along the following:
window.updateGUI = function () {...}
If you want to add a number of functions to the global scope, it's better to store them under a single object and address your functions through there. That helps avoid any possible collisions you might otherwise have.
var myFunctions = window.myFunctions = {};
myFunctions.updateGUI = function () {...};
After that you can simply call myFunctions.updateGUI();.
A better way do to that is to grant unsafeWindow.
// #grant unsafeWindow
Then create your function like this:
function test()
{
console.log("test");
}
But also make it available in console through unsafeWindow:
if(!unsafeWindow.test)
{
unsafeWindow.test = test;
}
Then you can access test in the console.
I found an answer to my question, but Nit's answer is superior. I will still post mine in case someone needs it.
You can add functions to global scope by adding them to a script element and appending it to body
var scriptElem = document.createElement('script');
scriptElem.innerHTML = 'function updateGui() { /* stuff */ }';
document.body.appendChild(scriptElem);
var scriptElem = document.createElement('script');
scriptElem.innerHTML = 'function updateGui() { /* stuff */ }';
document.body.appendChild(scriptElem) Yes this works 100%

can't access variables in another javascript file

So i have link every file needed into the index.html file :
<script src="jquery.js"></script>
<script src="notify.js"></script>
<script src="script.js"></script>
i create an object in 'notify.js' :
var notify = {
newNotification : function(text) {
}
}
script.js :
alert(notify.newNotification);
When i try to access the 'notify' object in 'script.js', it works just fine.But i want to use jquery so i add $(document).ready() to both of the file like this:
notify.js
$(document).ready (
function() {
var notify = {
newNotification : function(text) {
}
}
}
)
Script.js:
$(document).ready (
function() {
alert(notify.newNotification);
}
)
And after i add that, it comes up with notify is not defined.What's wrong? Can anyone explain why it doesn't work?
As you have defined var notify in notify.js inside $(document).ready( which is an anonymous function and var notify scope is limited to this function only .
So it is not accessible outside the $(document).ready( function
To make accessible outside don't wrap it in $(document).ready( function
like this:-
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) { }
}
});
Like everyone else here already pointed out: Only use $().ready when you're handling DOM-Elements and your Variable is not accessible because you used the var keyword (like you're supposed to). The var keyword limits the defined variables to the current scope, which is the scope of the anonymous function you use as your DOM-Ready-Handler.
So, removing the unnecessary $().read will temporary solve your problem.
BUT(!) you should wrap your code into a closures to avoid messing up the global scope and to avoid possible naming conflicts with 3rd-party code.
Like that:
notify.js
;(function ($, window, undefined) {
var notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(notify.newNotification());
})(jQuery, this);
So, now you'll have the same problem as before, you don't have access to your Object.
Sure you could just add your notify Object to the global scope as Arun P Johny suggested in his answer, but i'm pretty sure over the time there will be more Object you'll need to make global accessible.
If you put each of them in the global scope, you start messing up the global scope again, so my recommendation would be ONE global Object that will hold all other objects/variables you need globally accessible. (Or even better use something like requirejs
Somethink like this:
main.js
;var MyApp = {}; # Only variable in global scope
# Maybe some more initalization code here, dunno
notify.js
;(function ($, window, undefined) {
MyApp.notify = {
newNotification : function(text) {
return text;
}
};
})(jQuery, this);
script.js
;(function ($, window, undefined) {
alert(MyApp.notify.newNotification());
})(jQuery, this);
Some interesting Q/A's about scope and closures here on stackoverflow:
What is the scope of variables in JavaScript?
How do JavaScript closures work?
JavaScript closures vs. anonymous functions
A good Answer about messing around with the global scope:
What is meant by “leaking” into global scope?
In this case there is no need to wrap the notification object in dom ready... because from the looks of it you are not creating any dom element reference while creating the object... the only thing that matters is any method invokation that deals with dom element has to be done on dom ready.
var notify = {
newNotification: function (text) {}
}
$(document).ready(function () {
notify.newNotification()
})
if you declare the variable inside a dom ready handler then it becomes a local variable to the dom ready handler... so it will not be accessible outside the dom ready handler...
Another solution is to add the variable to the global scope within the dom ready handle like
var notify;
$(document).ready(function () {
notify = {
newNotification: function (text) {}
}
})
or
$(document).ready(function () {
window.notify = {
newNotification: function (text) {}
}
})
You only need one document.ready
And this only declare the variables that will move freely in their scripts.
See the example:
script.js:
$(document).ready(function(){
// declare the variables as global
$.varA, $.varB, $.varC;
});
notify.js:
function doNotify(){
// your code here
$.varA = /*your code here */
}
function otherFunc(txt){
// your code here
$.varB = txt;
}
All of your JavaScripts will load before the document is ready.
Create a separate function in script.js that references the notify object, then call that function from $(document).ready
Try this.
var notify = {
newNotification : function(text) {
}

encapsulating javascript inside a namespace

I'm looking to encapsulate my javascript inside a namespace like this:
MySpace = {
SomeGlobal : 1,
A: function () { ... },
B: function () { ....; MySpace.A(); .... },
C: function () { MySpace.SomeGlobal = 2;.... }
}
Now imagine that instead of a few lines of code, I have about 12K lines of javascript with hundreds of functions and about 60 globals. I already know how to convert my code into a namespace but I'm wondering if there's a quicker way of doing it than going down 12K lines of code and adding MySpace. all over the place.
Please let me know if there's a faster way of doing this.
Thanks for your suggestions.
I like to wrap up the namespace like so. The flexibility is huge, and we can even separate different modules of the MySpace namespace in separate wrappers if we wanted too. You will still have to add some sort of _self. reference infront of everything, but at least this way you can change the entire name of the namespace very quickly if need be.
You can see how with this method you can even call _self.anotherFunc() from the 1st module, and you'll get to the second one.
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.test = function () {
alert('we got here!');
_self.anotherFunc(); // testing to see if we can get the 2nd module
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
$(function () {
MySpace.test(); // call module 1
MySpace.callOtherModule(); // call module 2
});
// Here we will create a seperate Module to the MySpace namespace
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.callOtherModule = function () {
alert('we called the 2nd module!');
};
_self.anotherFunc = function () {
alert('We got to anotherFunc from the first module, even by using _self.anotherFunc()!');
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));​
jsFiddle DEMO
Wrap a function body around your existing code to use as scope, hiding everything from global - this will allow you to do internal calls without pasting Namespace. prefix everywhere, neatly hide things you don't want everyone else to see, and will require minimal changes as well.
After that, decide what functions you want to "export" for everyone and assign them to properties of object you want to use as "namespace".

Loading multiple scripts with same variables/functions

Is it possible to load multiple scripts with same variables/functions in JS, without overriding the old value of the variable. For example to create an own scope/sandbox or object for each loaded script.
Files to load:
script1:
<script>
function init() {
do something...
}
</script>
script2:
<script>
function init() {
do something...
}
</script>
And after loading call script1.init() or script2.init(), is this possible?
You could wrap each section of code with a self invoking anonymous function, which will effectively namespace that section.
(function() {
function init() {
// do something...
}
})();
init(); // ReferenceError
However, if you can't change the code, the second init will overwrite the first definition.
However...
And after loading call script1.init() or script2.init(), is this possible?
...is confusing. Do you already have the init() as methods of an object? If so, they won't overwrite each other.
Unfortunately, no. There is a single global scope on a single page.
However, by using something like the module pattern, you can make a fake namespace:
For example:
var script1 = (function() {
var that = {};
that.init = function() {
do something...
};
more functions...
return that;
})();
And then call it by using script1.init();
You can find out more about the module pattern here.

Categories

Resources