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.
Related
I have javascript file called screener.js
function ScreenerPage() {
function onScreenListChange() {
do stuff
};
}
from the index.html file I include the javascript file like this:
<script type="text/javascript" src="./js/screener.js"></script>
Then later in the head section of index.html I instantiate the screenerPage object like this:
<script type="text/javascript">
$(document).ready(function () {
screenerPage = new ScreenerPage();
}
</script>
Then down in the body section there is a select with onchange event that calls
<select id="screenList" onchange="screenerPage.onScreenListChange()">
but the browser shows error:
Uncaught TypeError: screenerPage.onScreenListChange is not a function
What am I doing wrong?
The way javascript works is it has objects and the way of which they are created matter!
Here is the way i've found that works for this kind of thing
screener.js
var ScreenerPage = function() {
this.onScreenListChange = function() {
//do stuff
console.log("test")
}
}
Later on
var a = new ScreenerPage();
a.onScreenListChange();
if you have any questions on how it works feel free to try to message me!
The reason it does not work is that you're having a scope issue.
The function ScreenerPage is defined in the global scope, meaning it is accessible anywhere. Now inside that function you define a local function called onScreenListChange.
You are able to do that, but that function only exists within the scope of the function you defined it in.
When I look at your function, I think you want to use classes. A class is a single name that can have multiple variables / methods to do a specific task.
class ScreenerPage {
constructor(text){
this.onScreenListChange(text) // Call this "method" on object creation.
}
onScreenListChange(text) {
console.log(text ? text : 'do stuff');
};
}
var a = new ScreenerPage('hi'); // now watch your console log.
a.onScreenListChange();
I am creating the following code in JavaScript (inside file1.js)
function ABC () {
this.property01 = true;
}
ABC.prototype.doSomething = function () {
if (this.property01 == true) {
// Do something
}
}
Then later in a separate file in my project (lets call it file2.js), I have the following jQuery:
$(document).ready(function() {
var abc = new ABC();
// Some code here
abc.doSomething();
// continue with code
});
So far, everything is correct.
Now, what I would like to do is inside the prototype definition of doSomething() in file1.js, I want to use jQuery. Something along the lines
function ABC () {
this.property01 = true;
}
ABC.prototype.doSomething = function () {
if (this.property01 == true) {
$('#find-element'). .... // ... Do Something
}
}
But I am not sure how to do this. If I wrap the code of file1.js with a jQuery document-ready wrapper, then the line var abc = new ABC(); inside file2.js will throw an error because it no longer recognizes the function definition in file1.js.
Can I use jQuery inside a prototype the way I explained above? How can I do that? How can I structure my files to allow for this to happen?
This should work just fine just as long as jQuery has fully loaded before file1.js and file1.js have. If you explicitly load them in the correct order, the $ will be available globally, and the other files shouldn't have an issue recognizing that object. In fact, if you load things correctly, you shouldn't even need a document-ready setup to gain access to $.
<script src="../jquery.js"></script>
<script src="../file1.js"></script>
<script src="../file2.js"></script>
If, for some reason, you're having conflicts with the $ object, you could also just use the word jQuery to make your calls: jQuery('#find-something')
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) {
}
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);
I have a file called function.js which has all my jQuery for my aplication which looks like this
$(document).ready(function(){
insert_initial(); //first time to the page, insert into cart and set the subtotal originally
function update_gallery(product_id){
...
}
function update_prices(product_selector){
...
...
}
function insert_initial(){
...
}
$('.trigger').click(function(){
$('.stations').find(".drop-down").slideToggle();
return false;
});
...
...
On the top of the file i have my function call insert_initial(); which gets run on the initial load....and this works great..My problem is that i now need to include this js file on my php pages say 1.php and 2.php and 3.php and 1.php is the only one that needs the insert_initial(); ....so i was thinking of the best way to do this. I assumed taking out the function call out of the functions file and putting it into a separate file
<script src="/someting/js/functions.js" type="text/javascript"></script>
<script src="/someting/js/functions_insert.js" type="text/javascript"></script>
and in my functions_insert.js file i would have only
$(document).ready(function(){
insert_initial(); //first time to the page, insert into cart and set the subtotal originally
});
but that didnt work either...any ideas on how to fix this
This checks to make sure that the location of the current page includes "1.php" before calling insert_initial():
if(window.location.href.indexOf('1.php') != -1)
insert_initial();
I would recommend having your definitions and executions separate in this instance. You don't need to define your functions inside of jQuery's DOM ready event. But it is also good to namespace them as mentioned. A common paradigm I follow is like so:
functions.js
(function($, window, undefined) {
function update_gallery(product_id){
...
}
function update_prices(product_selector){
...
...
}
function insert_initial(){
...
}
window.MyApp = {
update_gallery: update_gallery,
update_prices: update_prices,
insert_initial: insert_initial
};
})(jQuery, window);
1.php
<script src="functions.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
MyApp.insert_initial();
});
</script>
Now you can include your definitions as needed, and call them as necessary.
Try namespacing your functions and attaching them to a nice global object.
window.MyApp = {};
MyApp.insert_initial = function(){
};
Then you can access it from wherever you need, provided it's included earlier in the page.
Edit:
If this doesn't work, you've got an error elsewhere in your code - load order, perhaps? Either method you've described to invoke the function is fine, just make sure it's defined when you invoke it.
Your functions defined in functions.js are only visible in the scope of that document ready function. A simple case where it doesn't work:
(function() {
function square(x) {
return x*x;
}
})();
alert(square(2)); //Fails, since square is not in scope
The easiest way to fix this is to declare your functions in the global namespace:
function square(x) {
return x*x;
};
alert(square(2)); //4