Using Node.
Trying to avoid global vars, but I need to share a variable(integer) between two functions that are not nested. Both functions are declared directly under the global scope.
Is something like this considered a good practice for what I'm trying to accomplish? If not, is there a better pattern to follow?
function doStuffWithDataFromEventListener(){
var a = inner2().num;
}();
var fakeListener = function(){ //make believe event listener that is only called once.
var num = 7;
return {num: num};
};
Use the module pattern:
// Global scope
(function(){
// Function (module) scope
var x = 5; // Module level (not global) variable
function a(){
return ++x;
}
function b(){
return ++x;
}
a(); // 6
b(); // 7
}());
There are several ways to control/prevent global variables is to create a closure function and put all your code in there. All code will be in the DOM as an anonymous function. You can also give that function a name so it will be easier to test. You can also create a global object and attach all your methods, variables, and properties onto that. I'm sure you've seen this before.
var myAppObj = myAppObj || {};
myAppObj.name = "tommy";
MyAppObj.odStuffFunc = function() {
// do stuff
};
Related
According to the Closures concept it will store the variables of the outer lexical environment for future execution of its inner function. For example:
function makeYounger(age) {
function b() {
console.log("Original age is :" + age);
}
b();
return(function() {
return age / 2;
});
}
var displayAge = makeYounger(20);
console.log(displayAge());
In the above scenario, age is preserved by the Javascript engine to execute the inner function present in the return method.
Here comes the IIFE:
(function(window) {
var greeting = "Hello";
var fNameSpace1 = {
name : "Appu",
callName : function() {
console.log(greeting + fNameSpace1.name);
}
};
window.doer = fNameSpace1;
}) (window);
fNameSpace1.callName(); //To execute the inner function
In the above scenario according to the closures concept the variables greeting and fNameSpace1.name will be stored for future execution of the callname() function. Instead we are making use of the window object. I am confused why we are going with window if we have closures?
IIFE is useful to avoid global variable pollution when multiple functions are accessing a global variable
Closure functions are helpful when working with a local variable.
Difference between closures and IIFE's in javascript
An IIFE is just one specific way to A) Create a closure over the context in which it's defined, and B) Create a context in which to create other closures.
My question is what is the exact use of window object in this scenario if the javascript engine already stores fNameSpace1 object.Why are we creating a reference using window?
So it can be used outside the IIFE, by referring to it via the doer global that window.doer = ... creates.
There are dozens of different ways to do this. One of them does it by assigning to window like that. Another does it by returning the value and using a var statement:
var doer = (function() {
// ...
return fNamespace1;
})();
but again, there are dozens of different formations. The author of that particular one just preferred to write to a property on window as the way to create the global.
JavaScript normally follows the function scope i.e. variables are accessible only within the function in which they are declared.
One of the ways to break this convention and make the variable accessible outside the function scope is to use the global window object
e.g.
window.myVar = 123;
My question is are there any other ways in JavaScript/jQuery to make the variable accessible outside the function scope?
Not with variable declarations, no. You can obviously declare a variable in an outer scope so that it's accessible to all descendant scopes:
var a; // Available globally
function example() {
a = "hello"; // References a in outer scope
}
If you're not in strict mode you can simply remove the var keyword. This is equivalent to your example:
// a has not been declared in an ancestor scope
function example() {
a = "hello"; // a is now a property of the global object
}
But this is very bad practice. It will throw a reference error if the function runs in strict mode:
function example() {
"use strict";
a = "hello"; // ReferenceError: a is not defined
}
As you wrote, variables are only visible inside the function in which they were defined (unless they are global).
What you can do is assign variables to the function object itself:
function foo() {
foo.myVar = 42;
}
console.log(foo.myVar); // outputs "undefined"
foo();
console.log(foo.myVar); // outputs "42"
But I would advise against it. You should really have a very good reason to do something like this.
You can define them as part of a global object, then add variables later
// Define your global object
var myObj = {};
// Add property (variable) to it
myObj.myVar = 'Hello world';
// Add method to it
myObj.myFunctions = function() {
// Do cool stuff
};
See the link below:
Variable declaration
Also, you can declare it without the var keyword. However, this may not be a good practice as it pollutes the global namespace. (Make sure strict mode is not on).
Edit:
I didn't see the other comments before posting. #JamesAllardice answer is also good.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to avoid global variables in JavaScript?
I'm looking for some advice on how best to manage global variables in JavaScript.
Consider the following:
foo = 1;
bar = 2;
// Update our global variable
function doStuff (newFooValue) {
foo = newFooValue
}
// Update a global based on a condition
function doMoreStuff () {
if (bar == 3) {
foo = 1;
}
}
In both cases, our functions are accessing global variables internally, which feels ugly to me. From what I've read, we want to avoid globals as much as possible to avoid clogging up the global name space.
So is creating a structure for our globals all that we need?
For example,
var myPage = {}
myPage.foo = 1;
myPage.bar = 2;
I suppose this solves the global namespace collision problem, but I am still accessing the global scope from within my methods.
What should I do?
To avoid global namespace pollution you should wrap your code in an Immediately Invoked Function Expression (IIFE). JavaScript variables have functional scope so they only exist within the function they're declared in.
(function () {
//these variables only exist within the outer function
var foo,
bar;
foo = 1;
bar = 2;
//these functions only exist within the outer function
function fizz() {
return foo + bar;
}
function buzz() {
return foo - bar;
}
}());
The above example is pretty useless, as all the variables and functions are encapsulated and won't be usable externally. Any functions/variables that need to be global should be manually added to the global object:
(function (g) {
//not repeating code from above, pretend it's here
//make the functions globally accessible
g.fizz = fizz;
g.buzz = buzz;
}(this));
Wrap it in a class maybe?
var myPage = {}
myPage.foo = 1;
myPage.bar = 2;
myPage.doStuff = function(newFooValue) {
this.foo = newFooValue;
}
You would just use one spot in the global scope then.
You should avoid this but if you need to address the global scope then you will do it.
If you are asking about design patterns you would have to be more precise.
If you have two functions named doStuff and doMoreStuff it is a very hard thing to design.
I have seen many js frameworks (including jquery) using closure around their main function scope. For example,
var obj = (function(){
return {
test : function(){
alert('test');
}
}
})();
obj.test()
jquery source,
http://code.jquery.com/jquery-1.7.2.js
Whats the need that extra 'closure' around the 'function'? Or whats the difference if we are using it like,
var obj = function(){
return {
test : function(){
alert('test');
}
}
}();
obj.test()
Both have the same behavior and function definition itself puts all the local variable inside a new scope... so why the extra closure?
It adds the "big"object\library functions, and not adding them to the global object.
The two options you pasted are just like the difference between:
var foo = (2);
var foo = 2;
No difference...
Update:
Now I undersatnd your question, parentheses don't create new scope in javascript, only functions.
That is just a convention to be able to easily distinguish self-executing functions from normal functions.
I have no idea why it didn't work if I specify a variable with 'var':
like this:
var mytool = function(){
return {
method: function(){}
}
}();
And later I use it in the same template: mytool.method. This will output mytool was not defined.
But if I define it like this:
mytool = function(){
return {
method: function(){}
}
}();
Then it works.
Javascript has function scope. A variable is in scope within the function it was declared in, which also includes any functions you may define within that function.
function () {
var x;
function () {
// x is in scope here
x = 42;
y = 'foo';
}
// x is in scope here
}
// x is out of scope here
// y is in scope here
When declaring a variable, you use the var keyword.
If you don't use the var keyword, Javascript will traverse up the scope chain, expecting to find the variable declared somewhere in a higher function. That's why the x = 42 assignment above assigns to the x that was declared with var x one level higher.
If you did not declare the variable at all before, Javascript will traverse all the way to the global object and make that variable there for you. The y variable above got attached to the global object as window.y and is therefore in scope outside the function is was declared in.
This is bad and you need to avoid it. Properly declare variables in the right scope, using var.
The code you have doesn't show enough to demonstrate the problem. var makes the variable being defined 'local' so it will only be available within the same function (javascript has function level scoping). Not using var makes it global, this is almost always not what you want. You might need to rearrange your code to fix the scope issues.
I take it that you're using this inside of some function:
function setup_mytool() {
var mytool = function(){
return {
method: function(){}
}
}();
}
This creates the variable mytool in the function's scope; when the function setup_mytool exits, the variable is destroyed.
Saying window.mytool or window.my_global_collection.mytool will leave the variable mytool intact when the function exits.
Or:
var mytool;
function setup_mytool() {
mytool = function(){
return {
method: function(){}
}
}();
}
will also do what I think it is you're intending.
The reason why you are getting variable undefined errors is because when you use var, the declared variable is scoped to the surrounding context, meaning that the variable's lifetime is limited to the lifetime of the surrounding context (function, block, whathaveyou).
If you don't use var however, you are effectively declaring a variable tied to global scope. (Usually a Very Bad Idea).
So, in your code, the reason why you are able to access the mytool variable somewhere else in your template is because you tied it to global scope, where in the case of using var, the variable went out of scope because it must have been declared within a function.