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;
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.
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've started using the Module pattern in a project of mine. As I understand it, it goes something like this:
var obj = (function(foo){
//Some initialization logic up here.
//Private methods
var privateBazz = function(){
return "I'm known only to this closure!";
}();
//Public methods
return {
publicFoo: foo,
publicBar: function(){
return foo + privateBazz;
}
}
})();
This looked pretty good on paper and, in practice, seems to work reasonably well. Initialization logic at the top is intuitive, then private methods, then public.
I've encountered one issue, though. How should I call publicFoo or publicBar from outside the scope of the return statement and inside the scope of obj's function declaration?
My current solution is to do something like:
var obj = (function(foo){
//Private methods declared early for use.
var privateBazz = function(){
return "I'm known only to this closure!";
}();
var privateBar = function(){
return foo + privateBazz;
};
//Some initialization logic up here.
var dependentOnBar = privateBar();
//Public methods
return {
publicFoo: foo,
publicBar: privateBar
}
})();
This works, but suddenly the declarations of my private variables are placed above my objects private property declarations. The problem becomes exacerbated if I attempt to keep the private function declarations as close to the code which first calls them, so I have just been declaring all the private functions I need at the top, then initializing properties afterwards. Again, this works, but I am used to having code as close to the execution point as possible. So, declaring blocks of private functions at the top is really awkward to me. Does anyone else feel this way, or is this something I just need to get over for JavaScript? Are there any steps I should be taking when I see this happening?
It sounds like you could solve this problem by simply not using object notation to return the module, but rather initialize it and build it as you go. This would go something like this:
var obj = (function(foo){
var self = {};
//Some initialization logic up here.
//Private properties
var foo = "only accessible within this scope";
//Private methods
var privateBazz = function(){
return "I'm known only to this closure!";
}();
//Public Properties
self.publicFoo = foo;
//Public Methods
self.publicBar = function(){
return foo + privateBazz;
};
return self;
})();
here is my solution: if you declare everything before the return as a "private" method and make public those you want to, then you can call your private from within the public and vice versa (in your first sample, your privates can't call the publics as they are not declared at that moment)
var obj = (function() {
// All functions now have direct access to each other
var privateFunc = function() {
return "private "+publicFunc1();
};
var publicFunc1 = function() {
return "public 1 ";
};
var publicFunc2 = function() {
return "public 2 "+publicFunc1();
};
var publicFunc3 = function() {
return "public 3 "+privateFunc();
};
// Return the object that is assigned to Module
return {
publicFunc1: publicFunc1,
publicFunc3: publicFunc3,
publicFunc2: publicFunc2
};
}());
alert(obj.publicFunc3());
If you emulate CommonJS Modules, you can assign properties to the exports object as well as accessing them from elsewhere within the IIFE scope via qualified or unqualified name.
(function (exports, undefined) {
var priv1 = 42;
exports.pubOne = function () {};
var localAlias = function () {};
localAlias(42);
exports.pubTwo = localAlias;
})(window.App);
In this example, Window.App might be my namespaced global object for this module, but you could pass in an empty object or some deeply nested namespace just as easily.
I'm a javascript newbie, and I've come up with the following scheme for namespacing:
(function() {
var ns = Company.namespace("Company.Site.Module");
ns.MyClass = function() { .... };
ns.MyClass.prototype.coolFunction = function() { ... };
})();
Company.namespace is a function registered by a script which simply creates the chain of objects up to Module.
Outside, in non-global scope:
var my = new Company.Site.Module.MyClass();
I'm particularly asking about the method by which I hide the variable ns from global scope - by a wrapping anonymous function executed immediately. I could just write Company.Site.Module everywhere, but it's not DRY and a little messy compared to storing the ns in a local variable.
What say you? What pitfalls are there with this approach? Is there some other method that is considered more standard?
You dont need to scope classes like that, its only necessary if you have global variables outside of the class. I use this approach...
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = {
foo: function() {
}
};
Also note that I use a object literal for a cleaner prototype declaration
However if you need to scope global variables then you can do
(function() {
var scopedGlobalVariable = "some value";
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = function() {
foo: function() {
}
};
})();
Your approach looks fine to me.
However, you can also do this slightly different, by returning the "class" from the self-executing function:
Company.Site.Module.MyClass = (function() {
var MyClass = function() { ... };
MyClass.prototype.foo = function() { ... };
return MyClass;
})();
This strips at least all the ns. prefixes. The namespace function can still be utilized to create the objects, but outside of the self-executing function.
to call a function at the same time it's defined, i had been using:
var newfunc = function() {
alert('hi');
};
newfunc();
is the following the correct way of combining these 2:
var newfunc = function() {
alert('hi');
}();
There could be a number of reasons you wish to do this. I'm not sure what yours are, but let me introduce a couple of favourite patterns:
Pattern #1: A singleton. The function is executed and then becomes a singleton object for use by other components of your code.
var singletonObject = new function() {
// example private variables and functions
var variable1 = {};
var variable2 = {};
var privateFunction = function() {
};
// example public functions
this.getData = function() {
return privateFunction(variable1, variable2);
};
// example initialisation code that will only run once
variable1.isInitialised = true;
};
Pattern #2: Self-executing anonymous function ... handy for sooo many reasons!
// Declare an anonymous function body.
// Wrap it in parenthesis to make it an "expression.
// Execute it by adding "();"
(function(){})();
And here's an example that also creates a namespace for your objects.
I'm using "NS" as an example namespace:
// declare the anonymous function, this time passing in some parameters
(function($, NS) {
// do whatever you like here
// execute the function, passing in the required parameters.
// note that the "NS" namespace is created if it doesn't already exist
})(jQuery, (window.NS = window.NS || {}));
You can also set the context of a self-executing function by using .call or .apply instead of the usual parenthesis, like this:
(function($){
// 'this' now refers to the window.NS object
}).call(window.NS = window.NS || {}, jQuery);
or
(function($){
// 'this' now refers to the window.NS object
}).apply(window.NS = window.NS || {}, [jQuery]);
var newfunc = function f() {
alert("hi!");
return f;
}();
Having a named function expressions allows the function to recursively call itself or, in this case, return itself. This function will always return itself, however, which might be an annoyance.
No. Your second example will immediately call the anonymous function and assign its return value to newfunc.
adamse describes an approach which appears to work. I'd still avoid the approach as the two step process is easier to read and thus will be easier to maintain.
If I understand your question correctly, give this a try:
(f = function (msg) {
msg = msg ? msg : 'default value';
alert(msg); }
)();
f('I\'m not the default value!');
You'll get two alerts, the first one will say "default value" and the second will say "I'm not the default value. You can see it in action at jsBin. Click 'preview' to make it run.
you could do like this:
o = {};
o.newfunc = ( function() {
function f() {
alert('hi');
}
f();
return {
f : f
};
}
)();
then calling the function like:
o.newfunc.f();
will also render an alert message