I am trying to work out a style of javascript modular coding.
Currently I have a "mount variable" declared in a global.js that is linked to all the pages in a web application. It contains global site stuff, like javascript language switching:
var app = window.app || {};
app.Lang = (function ($) {
"use strict";
var init = function () {
...
};
};
return { init: init };
})($);
app.GlobalLogic = (function ($) {
"use strict";
var ready = $(function () {
app.Lang.init();
});
}($));
As you can see, I am using immediately executed functions to initialize the logic for a loaded code in the file.
Now I am trying to write an isolated javascript file that can have a similar variable names with other files loaded on the same page. Here is an example:
app.GalleriesAdminLogic = (function ($) {
"use strict";
var MountDivID = "#galleries-management-view";
...
var constructorFunction = function () {
var initialDataObject = $.parseJSON($(MountDivID + " #initial-galleries-list").val());
...
}($));
Notice the variable MountDivID. If there was a similar js file loaded at the same time, that would also contain a definition for variable named MountDivID, would it create a resolution conflict? What is the correct pattern to address a same name variables only from local function?
Variables declared inside functions are local to that function. They are not visible to other functions, and they "hide" variables with the same name declared outside the function.
Related
I have a module with a lot of JS code in it. Module is created like so:
(function (root, factory) {
// root === window
root.MyModuleName = factory();
})(this, function () {
'use strict';
var MyModuleName = function() {
// A lot of code here that I don't want to be parsed or evaluated
// until MyModuleName constructor is executed.
//
// For example:
// var a = { d: 123 };
// var b = function() { return 45; };
// this.someMethod = function() { b() + a.d };
// ...
};
return MyModuleName;
});
All methods & properties are inside MyModuleName closure and (I thought) they should be parsed only after MyModuleName() is executed.
After user clicks on some button I create an instance of MyModuleName and execute some method:
someButton.onclick = function() {
// I want compiler to parse and evaluate JS code only here
var myModule = new MyModuleName();
console.log(myModule.someMethod());
};
Even though MyModuleName constructor is executed() only after click, code inside it is evaluated when JS file loads (I can see it in Chrome dev tools timeline).
How to make sure compiler evaluates code only after click, not after JS file loads?
You can't. The JS engine has to evaluate the code to create the function before it can assign the function anywhere.
I am writing an application code in javascript.
I just want an expect advice on how Encapsulation be achieved in JS,
The pattern which I wrote is something like,
var app = (function (window) {
// define variables here
// define functions here
return {
init: function () {},
plotGraph: function () {},
plotTable: function () {},
resizeHanlder: function () {},
initMenu: function () {},
attachEvent: function () {}
}
})(this);
Is there anything better than this.
Why I am doing this?
I really do not want to pollute global scope
What you are trying to make is called revealing module pattern. Here is one link on this topic:
https://carldanley.com/js-revealing-module-pattern/
Let's short analyse your code:
There will be only one global variable app. It get assigned the result of an anonymous functions, which is self-executed (we'll see that in the last line), also called Immediately-Invoked Function Expressin (IIFE).
var app = (function (window) {
The function returns an object which is assigned to the variable app
return {
init: init,
plotGraph: function () {},
plotTable: function () {},
resizeHanlder: function () {},
initMenu: function () {},
attachEvent: function () {}
}
The following code will never be executed, as the function already returned a value in the previous step.
function init() {}
And this here makes the function self-executable.
})(this);
Since your code has errors I would give you a simple example how to implement the revealing module pattern:
var hello = (function () {
var sayHello, makeGreeting;
sayHello = function () {
return 'Hello, ';
};
makeGreeting = function (name) {
console.log(sayHello() + name);
}
return {
makeGreeting : makeGreeting
};
})();
Now we have one object hello with one method makeGreeting. There is additional logic within which is not exposed to the end user, because he/she doesn't need to know it or isn't supposed to change those values.
Here is another example for this pattern from my GitHub:
https://github.com/cezar77/roman/blob/master/roman.js
how to access an object in the namespace.
1) i have a html which imports script files
one script defines the namesapce app and the other script attaches a object to it
how do i access the object and start using it
app.js
var app = (function(jQuery){
if (!jQuery) {
alert(app.resources["MISSING_LIB"]);
return null;
}
return {
init: function() {
//code for init the app related variables and subnamspaces
}
};
})(jQuery);
jQuery(document).ready(function(){
app.init();
});
personal.js
function(app){
if (app) {
app.Cache = function(nativeStorage,serializer ) {
this.storage = nativeStorage;
this.serializer = serializer;
}
app.Cache.prototype = {
setItem: function( key, value ){
this.storage.setItem(key, this.serializer.stringify( value ));
return( this );
}
};
var personalcontentstorage = new app.Cache(localStorage,JSON);
} else {
alert("app is undefined!");
}
})(app);
myhtml.html
<html>
<head>
<script src="${ '/js/app.js'" type="text/javascript"></script>
<script src="${ '/js/personal.js'" type="text/javascript"></script>
</head>
<body>
<h1>
Exploring HTML5's localStorage
</h1>
<script type="text/javascript">
jQuery(document).ready(function(){
personalcontentstorage.setItem("mykey","myValue") ;
});
</script>
</body>
</html>
How to access the object "personalcontentstorage" so that i can use its methods .I get a undefined error when accesing hte object.I cannot access the object the way i have written above
There is a problem in app.js, the app variable is not what you think:
var app = (function(jQuery){
// function body
})(jQuery);
What is being assigned to app is the return value from the self-executing anonymous function after the equal sign. Which is undefined (or null, in case jQuery is falsey). You have to have the function return something to be assigned to the app var.
You can't just reference a variable declared in another scope like that. That's why scope exists. If you want to grab the personalcontentstorage variable, just return it:
// assign your IIFE to a variable
var something = (function(app){
if (app) {
// snip
return new app.Cache(localStorage,JSON);
} else {
alert("app is undefined!");
}
})(app);
jQuery(document).ready(function() {
// use the variable your IIFE's return was stored in
something.setItem("mykey","myValue") ;
});
How about returning it from your personal.js function?
var Personal = (function(app) {
if (app) {
app.Cache = function(nativeStorage, serializer) {
this.storage = nativeStorage;
this.serializer = serializer;
}
app.Cache.prototype = {
setItem: function(key, value) {
this.storage.setItem(key, this.serializer.stringify(value));
return (this);
}
};
var personalcontentstorage = new app.Cache(localStorage, JSON);
} else {
alert("app is undefined!");
}
return {
storage: personalcontentstorage
};
}(app));
Then in your HTML file, you'd just reference:
Personal.storage.setItem("myKey", "myValue");
Not sure if that's exactly what you're looking for. Your code is very hard to read and by your own admission it's not really your code, just something sort of like it. Please try to post your questions with well-structured, somewhat functional code. :-)
If you define a variable within a function, that variable isn't visible outside of the function, e.g.
(function () {
var foo;
}());
// foo is not visible here
The only variables that are visible everywhere are global variables (or more precisely, properties of the global object, which in a browser's case is window). These can be defined in three ways:
Use var, but not inside a function:
var foo;
(function () {
// foo is visible here
}());
// foo is also visible here
Explicitly attach your variable to the window object:
(function () {
window.foo = 7;
}());
// foo is visible here
Don't use var the first time you assign something to the variable. This is definitely the wrong way to do things: it's not obvious to someone reading the code that you intended to create a global variable.
Global variables have various risks and drawbacks. If you include third party scripts in your page they might use the same global variable names and interfere with your own scripts. It's generally best to keep the number of global variables you use to an absolute minimum.
I often use this pattern, creating a single global variable to contain all of the code for a project (you can replace MySite with the name of the project):
// Create a global variable that can contain everything else
window.MySite = {};
// Add something to the namespace
MySite.foo = (function () {
// Code that isn't visible globally here
return someValueForFoo;
}());
// Elsewhere in my code I can easily access `someValueForFoo`:
MySite.foo
Applying this to your project:
window.MySite = {};
// In app.js
MySite.App = (function (jQuery) {
// ...
}(jQuery));
// In personal.js
MySite.storage = (function (jQuery) {
// ...
return new MySite.App.Cache(localStorage,JSON);
}(jQuery));
// Elsewhere in your code
MySite.storage.setItem('foo', 'bar');
I have a "host" javascript closure, in which i keep all the common variables i am using over the website
var hostFunction = (function () {
var variableA = $("#variableA");
var variableB = $("#variableB");
// some usefull code here
} ());
In my website, in another javascript file, i have another closure
var childFunction = (function () {
var changeValue = function () {
variableA.html("I was changed");
};
// other usefull code
} ());
How is possible to insert "childFunction" inside "hostFunction" so i can get access to those variables?
What is the best practice of sharing variables across the website but also keeping them inside a scope so they don't conflict with other javascript variables?
If any information needs to be shared globally, it is best practice to use namespaces to mitigate the risk of your variables clashing with any others.
This blog post gives a reasonable introduction to namespacing in javascript.
I think you need the word this for those variables to be seen in other scopes
var hostFunction = (function () {
this.variableA = $("#variableA");
this.variableB = $("#variableB");
// some usefull code here
} ());
You pass in your host in the constructor of your childFunction like this:
var childFunction = (function (myHost) {
var changeValue = function () {
myHost.variableA.html("I was changed");
};
// other usefull code
} (hostFunction));
My javascript file is getting pretty big (3000+ lines) and I'm getting confused as to how to layout my file and delare functions so that they can called anywhere in the file.
To summarise my JS file looks a little like this at the moment:
//ALL GLOBAL VARIABLES FIRST DECLARED HERE
var var1 , var2 ,var3
$(document).ready(function(){
//JQUERY STUFF
});
//ALL FUNCTIONS THAT NEED TO BE GLOBAL DECLARED HERE
function myFunction(){
//do some stuff here
}
I am running into problems with this as some functions I call in places don't seem to be declared at the time of calling or aren't available globaly. It's all very confusing now!
Could someone suggest the best way to layout a big js/jquery file with certain JS Functions, Objects and Variables available to be referenced anywhere in the file.
UPDATE:
So to simplify it this correct (see my comments)?
window.MainModule = (function($, win, doc, undefined) {//WHAT IS BEING PASSED IN HERE?
var foo, bar, modules; //VARIABLES ACCESSIBLE ANYWHERE
var modules["foobar"] = (function() {//WHAT IS A MODULE? WHEN WOULD I USE A SEPERATE MODULE?
var someFunction = function() { ... };//DECLARING MY FUNCTIONS?
...
return {
init: someFunction,//IS THIS WHERE I USE/BIND MY FUNCTIONS TO EVENTS AND ELEMENTS?
...
};
}());
// hoist a variable into global scope
window.Global = someLocal;
return {
init: function() {//FUNCTION TO INIT ALL MODULES?
for (var key in modules) {
modules[key].init();
}
}
};
}(jQuery, this, document));
The modules section isn't properly defined ... here's a slightly tidied up example.
window.MainModule = (function($, win, doc, undefined) {
var modules = {};
// -- Create as many modules as you need ...
modules["alerter"] = (function(){
var someFunction = function(){ alert('I alert first'); };
return {
init: someFunction
};
}());
modules["alerter2"] = (function(){
var someFunction = function(){ alert('I alert second'); };
return {
init: someFunction
};
}());
return {
init: function(){
for (var key in modules){
modules[key].init();
}
}
};
}(jQuery, this, document));
$(window.MainModule.init);
// We always use closures don't we?
window.MainModule = (function($, win, doc, undefined) {
var foo, bar, modules; // List of local variables.
var modules["foobar"] = (function() {
var someFunction = function() { ... };
...
return {
init: someFunction,
...
};
}());
// hoist a variable into global scope
window.Global = someLocal;
return {
init: function() {
for (var key in modules) {
modules[key].init();
}
}
};
}(jQuery, this, document));
// Let's kick off the MainModule on $.ready
// I recommend you do this in your `html` with page specific data.
$(window.MainModule.init);
[[Disclaimer]]: This is a pseudo-code module with some standard code excluded for brevity.
Anything declared with var x inside your main closure is available throughout the entire function. Of course it won't be set to what you expect it to be set unless you set it.
To control loading and flow split code into what's automatically executed in your self executing closure and what needs to manually inited by your controller with page/user specific parameters.
You can either declare them in Window scope:
window.variableName = myVariable;
or you can omit the var, which is the same as declaring something in window scope:
variableName = myVariable;