I'm studying variable scope in Javascript, and have come across the difference between variable declaration, and variable initialization. From talking to a developer I know, my understanding is that writing var before a variable declaration assigns the variable to the local scope, while not writing var before declaring the variable assigns the variable to the global scope. Is this true?
If writing var before declaring a variable does assign the variable to the local scope, is it necessary to write var later, when initializing the variable to keep it in the local scope? For example:
var someVariable;
// Do some things with JavaScript
someVariable = 'Some Value'
Since I declared someVariable in the local scope with var, but then initialized someVariable without using var, does JavaScript think that I just initialized one variable in the local scope, or that I declared one variable in the local scope, and then declared and initialized another variable in the global scope?
Later on, when I want to change the value of someVariable again, do I need to write var before the variable expression, or will JavaScript know that I'm changing the value of an already declared local variable? Technically speaking, how does JavaScript know when I'm changing the value of an already declared local variable, and when I'm declaring and initializing a global variable?
var something = "Initial value."
This means: "create a variable in the local scope and give it an initial value". The local scope means the function in which you use this statement.
something = "New value."
This means: "find variable 'something' in the nearest scope, and assign it a new value".
If you use the second statement without ever using the first, the statement will look for any definition of something in progressively bigger scopes (the function that contains your function, if it exists, the function that contains that, etc., until it reaches the global scope). If it finds something, it will assign to an already existing variable. If it finds nothing, it will create a global variable with that name.
If you use var first, you simply ensure that this search always stops at local scope.
These are the same:
var x;
// ...
x = 1;
...and...
var x = 1;
Both define a variable in the local scope and assign a value to it. If you want to change the value of the variable later in the same scope you can simply reference it by name:
x = 2;
If you're in a different scope however, unless the variable was declared in the global scope in the first place you will not be able to access it (it's "out of scope"). Attempting to do so will define a variable with that name in the global scope.
function a(){
var x = 1;
}
function b(){
x = 2; // 'x' in a is out of scope, doing this declares a new 'x' in global scope
}
a();
b();
When referencing a variable in the same scope it was declared, you do not need to prefix it with var, though you can:
var x = 1;
// ...
var x = 2;
...there's no need to do that. While it assigns 2 to 'x', it logically has no effect since var is already in local scope. If x had been declared globally however:
var x = 1;
function a(){
var x = 2;
console.log(x);
}
a();
console.log(x);
This will print first '2' and then '1'. By referencing x preceded with var in the function, it applies the local scope to the variable. Once the function completes the variable's original scope is restored (or the re-scope is lost, if you want to look at it that way). Thanks to #zzzzBov for pointing this out.
Hope this helps.
my understanding is that writing var before a variable declaration assigns the variable to the local scope, while not writing var before declaring the variable assigns the variable to the global scope. Is this true?
Not entirely.
function foo() {
var a = 1;
function bar() {
a = 2; // Still in the scope of foo, not a global
}
}
Since I declared someVariable in the local scope with var, but then initialized someVariable without using var, does JavaScript think that I just initialized one variable in the local scope, or that I declared one variable in the local scope, and then declared and initialized another variable in the global scope?
There is only one someVariable in that example.
Later on, when I want to change the value of someVariable again, do I need to write var before the variable expression
var scopes a variable for the entire function, no matter where in the function it appears.
If you define a variable using var, you can refer to the same variable without using the var keyword over and over. These refer to the same variable:
var someVariable;
//...code...
someVariable = 'rawr';
If you did use the var keyword every time you were changing the variable, you wouldn't get separate variables. The newest declaration would just overwrite the oldest declaration. So there's no point in using the var keyword except for initialization. To change the value of someVariable, you can just make assignments to the variable name like in the above example.
Basically, using var will create a new variable if there is no variable in that scope with the same name.
Now take this code for example:
var someVariable = 'initialized';
function test1(){
//this someVariable will be a new variable since we have the var keyword and its in a different scope
var someVariable = 'test1';
console.log(someVariable);
}
function test2(){
//because there is no var keyword this refers to the someVariable in the parent scope
someVariable = 'test2';
console.log(someVariable);
}
console.log(someVariable); //initialized
test1(); //test1
console.log(someVariable); //initialized
test2(); //test2
console.log(someVariable); //test2
With this example you can see that depending on what you want the code to do, you could be having problems. If you wanted test2 to act like test1 and forgot to use the var keyword you would be confused when you were expecting someVariable to be initialized and instead it was test2.
But you could have also purposely not used the var keyword because you wanted test2 to update the parent variable. So it is important that you use the var keyword correctly.
Not using var when initializing variables will create the variable on the global scope. This is not good practice. If you want variables on the global scope, manually put them there. i.e. window.someVariable = 'initialize'; That way anyone else that sees your code knows that you made it a global variable on purpose.
Related
I learnt about the term variable shadowing in Eloquent Javascript (Chapter 3), but I am trying to understand a precise, basic example of the concept.
Is this an example of shadowing?
var currencySymbol = "$";
function showMoney(amount) {
var currencySymbol = "€";
console.log(currencySymbol + amount);
}
showMoney("100");
That is also what is known as variable scope.
A variable only exists within its containing function/method/class, and those will override any variables which belong to a wider scope.
That's why in your example, a euro sign will be shown, and not a dollar. (Because the currencySymbol containing the dollar is at a wider (global) scope than the currencySymbol containing the euro sign).
As for your specific question: Yes, that is a good example of variable shadowing.
In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. This outer variable is said to be shadowed...
so I believe your example is good.
you have a globally named variable that shares the same name as inner method. the inner variable will be used only in that function. Other functions without that variable declaration will use the global one.
Yes, your example is an example of shadowing.
The shadowing will persist in other scenarios too due to how closures work in JavaScript. Here's an example:
var x = -1;
function xCounter() {
var x = 0;
return function() {
++x;
return x;
};
}
console.log(x); // -1
counter = xCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(x); // still -1, global was never touched
Note that in this case, even when xCounter returns, the function it returns still has a reference to its own x and invocations of that inner function have no effect on the global, even though the original has long since gone out of scope.
We cannot define a variable more than once. But we can define in different scopes.
let name="tara"
if(true){
let name="ali"
if(true){
console.log(name)
}
}
variable shadowing is when a variable in a local scope uses its value instead of a variable in a parent scope.So the local variables value is shadowing over the parents.
in the above code there are two name variables defined but they are not defined in the same scope. so console.log(name) will check the local scope if it finds the name variable it uses it, if not it checks parent scope once finds it, it uses that one so it does not go the root.
var role = "Engineer";
console.log(role);
function displayRole(){
role = "developer";
console.log(role);
}
displayRole();
console.log(role);
Notice how the last line of code (console.log) prints developer yet it’s not inside the function scope. This is a good example of shadowing where by the role variable in the global scope has been overwritten by the role in the function scope.
To avoid shadowing, the variable in the function scope should be declared using the var keyword so that it becomes accessible to the function only.
Yes, this is a good example of shadowing. A global scope variable is said to be shadowed by a block scope variable when both have the same name. This is happening in your code and the block scope is shadowing the global scope.
I don't understand why a var variable can be reassigned within a function, but the change also applies outside of the function. Why/How?
var c = 1;
function Fn() {
c = 2;
}
Fn();
c; // 2
Why isn't the value 2 limited to the scope of the function?
When I write c = 2 within a function, does the javascript engine automatically hoist a new var c outside of the function and assigns it the value undefined, which is then changed to 2 once Fn() is called?
It applies outside the function because, inside the function, you are changing the variable.
You are not creating a new variable that exists only inside the function.
Why isn't the value 2 limited to the scope of the function?
You didn't use var, let, const or any other method to create a variable in the scope of the function.
You are accessing the variable you already created in the wider scope.
When I write c = 2 within a function, does the javascript engine automatically hoist a new var c outside of the function and assigns it the value undefined, which is then changed to 2 once Fn() is called?
No. There isn't a new variable. There is only the c you already created outside the function.
This is a common complaint about javascript. Since you used "Var" it has a global scope, so even though you're within a new function when you use c=2 since it's already defined globally it's changed globally. Using "Let" helps define things local to the function and "const" defines globals as constants so they cannot be changed. This issue is particularly fun when you have two global variables with the same name in different JavaScript files and then reference both files to be used on a page. Globals should be used with caution.
When you start run this program, engine will store your variable which declared with "var" keyword in global object(window) then move on to get in the function, Engine will create Special Scope for function is called "Function Execution Context" (FEC) every declaration within the function will be available in this scope(FEC), so when Engine execute body of your function will find re-assignment for variable is called "c", it will looking for it in current scope, if didn't find it, will move on parent scope, in this case, Global Scope is its destination, will find the searched variable and then re-assign it with new value.
Read this wonderful article -> execution-context-how-javascript-works-behind-the-scenes
var a="abc";
function(){
var a="efg";
console.log(a);//I need global variable value "abc" here
}
function();
I need the value "abc" in the console. How can I get global variable value?
How can I get global variable value?
use window.a
var a = "abc";
function a1() {
var a = "efg";
console.log(window.a);
}
a1()
In your specific example, since you used var at global scope, you can access it on the global object, which is accessible via the window global on browsers; so window.a:
var a="abc";
function example(){
var a="efg";
console.log(window.a);//I need global variable value "abc" here
}
example();
However, if that global were created by using const, let, or class at global scope, e.g.:
let a = "abc";
...you would not be able to access it at all within that function, because even though globals created via const, let, or class are globals, they are not properties of the global object.
How can I get global variable value a?
By not naming your local variable a as well.
var a = "abc";
function example(){
var b = "efg";
console.log(a); // The global variable with the value "abc"
console.log(b); // The local variable with the value "efg"
}
example();
It's local to your function anyway, so you can rename to it anything you want without impacting other functions. Don't use names that you need to access global variables.
My tests suggest that the title is, indeed, correct. But I don't know if there is some subtle nuance that I'm not thinking of. See also: Is there anything wrong with declaring your vars inside of a for loop or an if block?
If they are in the same scope, your test is right. Redeclaring the same variable in the same scope does nothing.
But, if they are not in the same scope, re-declaring a variable in a local scope will create a new variable that will override the original within that scope.
So, this works fine:
var value = "foo";
var value;
console.log(value); // "foo"
But, this creates a new variable in the local scope that does not have the value of the globally defined one:
var value = "foo";
function test() {
var value; // this creates a new variable that is separate
// from the globally declared one with the same name
console.log(value); // undefined
}
test();
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.