Javascript scope issue: variable not being identified - javascript

I have two functions, one function calling the other.
Below is a simple analogy I created of the structure of code which I have:
function test1(){
alert(a);//a is not identified here even when test1() is called under test2 which has a defined in scope
alert(b);//b is identified here
}
function test2(){
var a = 'a';//Defining a
test1();//Calling test1()
}
var b = 'b';
test2();
As per the code above, function test1() is able to identify variable b but not variable a.
My question is that why variable a is not in the scope of test1 function even when we are calling test1() inside test2() which defines variable a?
Thanks in advance.

Functions remember their scope chain at the time they're being created, not at the time they're called.
Note that b gets "hoisted", so your code actually does this:
var b; // push b on scope chain
function test1(){ // store scope chain [b]
alert(a);
alert(b);
}
function test2(){ // store scope chain [b]
var a; // push a on scope chain
a = 'a';
test1(); //Calling test1() which still has scope chain [b], not [b,a]
}
b = 'b';
test2();

your expectation is wrong about the scope of the variables,
according to your code b is a global variable to 2 functions and a is in the scope of test2 function only because it is defined withing test2,
If you want something like you expected you can define test1 function in test2 scope like this,
function test2(){
var a = 'a';
test1();
function test1(){
alert(a);
alert(b);
}
}
var b = 'b';
test2();

JavaScript has 'function scope' which means that anything defined in a function is not visible outside of the function. So variable 'a' is not visible outside of test2. However, variable 'b' is a global variable so it is visible in every scope.
Function scope also means that inner functions get access to things defined in the outer function but that doesn't come in to play here...test1 is called from within test2 but it's not an inner function of test2. To see this in action you'd need to define the body of the test1 function within test2...
function test2(){
var a = 'a';//Defining a
test1();//Calling test1()
function test1(){
alert(a);//a is identified here because of function scope
alert(b);//b is identified here because it's global
}
}

It is a good practice to call the functions with arguments. This will make your code easily readable and maintainable. Just adding arguments to the functions make the code working:
function test1(a,b){
alert(a);
alert(b);
}
function test2(b){
var a = 'a';
test1(a,b);
}
var b = 'b';
test2(b);
If you don`t want to use arguments in the function declarations, a solutions is to use the arguments object inside the code:
function test1(){
alert(arguments[0]);
alert(arguments[1]);
}
function test2(){
var a = 'a';
test1(a,arguments[0]);
}
var b = 'b';
test2(b);
If you want you can make the arguments with default values. Since in JavaScript you can`t do it in the function argument list, it is done in the body of the function:
function test1(a,b){
a = a || 'a';
b = b || 'b';
alert(a);
alert(b);
}
function test2(b){
var a = 'a';
test1(a);//here b is not passed to the function and b will get the default value
}
var b = 'some new string for b';
test2(b);
Live on jsfiddle

According to your functions you have declared and defined the variable "a" within the function "test2()" so the scope of the variable "a" is restricted within that function itself and accessing the variable will return "undefined". But it is not in the case of the variable "b" which is declared and defined globally, So it can be accessed any where in the script part.
hope this helps you.

Related

Logic behind the two javascript function behaviour

Please explain what is the logic behind this two types of behaviour to understand easily.
var a = 10;
function foo(){
a = 20;
}
foo();
console.log(a);
Prints---> a = 20;
var a = 10;
function foo(a){
a = 20;
}
foo();
console.log(a);
Prints---> a = 10;
Because of the scope
In Javascript, when you assign a parameter in a function you define it in the scope of that function, regardless if a variable already exists with the name in the outer/global scope.
Update:
It is worth mentioning that with ES6's arrow functions you could still access the outer var if your function was defined in a parent class or function, using the this keyword.
Example
class Bar {
this.a = 10;
this.foo = function(a) {
this.a = 20;
};
this.foo2 = (a) => {
this.a = 20;
};
}
Not exactly the same but it is about scopes
Check the following code snippet
var a =10;
var b = a;
function foo(a){
// a here woukd refer to the parameter a and not the global variable, since it got overridden
console.log(a, b);
a= 20;
}
foo();
// prints the global variable a
console.log(a);
function bar(){
console.log(a, b);
// overrides the global variable a
a = 20;
}
bar();
// prints the global variable a
console.log(a);
the first one is because of global scope
var a =10;
function foo(){
a= 20;
}
here varieble a is accesed globaly and updated from inside the function global varieble can access every place
in the 2nd example just passing a referece of varieble a as a parameter and inside the function the recived parameter value get changed
var a =10;
function foo(a){
a= 20;
console.log(a)
}
foo();
console.log(a);
please run the second example of code in console then you can understand the change.
In the first example a in the function is replacing the first declaration of a outside the function because you're not scoping it locally with var (or let or const).
In the second example the function accepts a as an argument so it becomes scoped locally to the function. Note that this occurs even if a isn't actually passed into the function (and is therefore undefined).
A good article on scope and context that might be of some use to you.
In javascript, function variables has its own scope, if you used var,let,const or using variable as provided in formal parameters in function. if you don't use any of above variable's scope will be global.

Simultaneously Declaring Variables and Functions in JavaScript

Can anyone explain why
function x() {
console.log("Hello!");
}
var a = x;
a();
x();
produces
Hello!
Hello!
but this
var a = function x() {
console.log("Hello!");
}
a();
x();
throws an error when you try to call function x? Is the second x function not considered a hoisted function? I tried this in both nodejs and a browser.
What you have in the second example is what's called a named function expression.
Its name is not added to the containing scope, but is accessible within the scope of the function itself:
var a = function x() {
alert(x);
};
a();
This is useful in writing recursive functions or functions that otherwise reference themselves, as it ensures that the name won't get clobbered due to anything that happens outside the function's scope.
It also allows you to create self-referencing functions in places where you can't use a function declaration, such as in an object literal:
var myFavoriteFunctions = {
factorial: function f(n) {
return n === 1 ? 1 : n * f(n);
},
identity: function (v) { return v; }
};
console.log(myFavoriteFunctions.factorial(10));
Your first example is a function statement, which declares a name in its containing scope.
Your second example is a named function expression, which does not.
For more information, see here.

Javascript's Function constructor - scope issues?

This code new Function('fn', 'fn()') creates anonymous function which has param and (in this case the param is a function) executed.
Doing console.log(new Function('fn', 'fn()')) shows the output :
function anonymous(fn)
{
fn()
}
Now , the docs states :
Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.
Ok.
So why does this code yields 1 and not 44 ?
var a = 44;
function myFunc()
{
var a = 1;
function f()
{
alert(a)
}
new Function('fn', 'fn()')(f);
}
myFunc();
Why ?
What about this line above ?
they will only be able to access their own local variables and global
ones, not the ones from the scope in which the Function constructor
was called
It looks like the f is closure over the parent a , but how come ? it suppose to be run at global , and able to access local and global only !
What am I missing ?
Because you're invoking function f, which is a normal function that does create a closure.
The documentation refers to this:
var a = 44;
function myFunc()
{
var a = 1;
new Function('fn', 'alert(a)')(); //shows 44, not 1
}
myFunc();
In your example you call f function that defined inside myFunc function. Does not matter where you called it from. So you called you anonymous function that is defined in global scope and see a = 44, anonymous function called f function that is defined in myFunc scope and see a = 1.
I'm not sure what exactly you want to achieve with this code, but if you need 44 in your f you need to pass it there as an argument.
var a = 44;
function myFunc() {
var a = 1;
function f(myArgument) {
alert(myArgument)
}
new Function('fn', 'fn(a)')(f);
}
myFunc();

trouble understanding javascript function level scope

I have trouble understanding JavaScript function level scope, as a C# programmer it looks wired to me, I will try to explain it through code:
CODE#1
//Problem
//if same named variable (as in global scope) is used inside function scope,
//then variable defined inside function will be used,global one will be shadowed
var a = 123;
function func() {
alert(a); //returns undefined,why not just return 123 ?
//how come js knew that there is variable 'a' will be defined and used in
//this function scope ,js is interpreter based ?
var a = 1; //a is defined inside function
alert(a); //returns 1
}
func();
CODE#2
//when a variable(inside function) not named as same as the global,
//then it can be used inside function,and global variable is not shadowed
var k = 123;
function func2() {
alert(k); //returns 123 ,why not 'undefined'
var c = 1;
alert(c); //returns 1
}
func2();
So my questions are
in CODE#1 why first time a is undefined,why not it's just return 123? And how
come js knew that there is variable 'a' will be defined and used in
this function scope, js is interpreter based?
in CODE#2 why not k is 'undefined'?
http://jsfiddle.net/Nu2Vu/
CODE #1
Hoisting causes all variable declarations to be brought to the top of the scope, but it leaves the assignment where it is. When there is a reference to a variable JavaScript will first look in the current scope, if it doesn't find the variable it will continue to look up the scope chain until if finds the variable.
This code is interpreted something like this:
var a = 123; // global var named a declared, assigned a value
function func() {
var a; // the declaration of the local var a gets
// hoisted to the top of the scope, but the
// assignment is left below, so at the point
// it is initialized with a value of `undefined`
alert(a); // looks for a local var named a, finds it but
// it currently has a value of `undefined`
a = 1; // now the value is assigned to the local a
alert(a); // returns 1
}
func();
CODE #2
This code behaves the way it does because of closure.
A basic definition of closure is that JavaScript functions have access not only to variables defined in their own scope, they can also access variables available to their parent scope.
var k = 123; // declares and assigns a value to global k
function func2() {
alert(k); // looks for a local var named k, doesn't find it,
// looks in its parent scope (the global scope in
// this case) finds k, returns its value of 123
var c = 1;
alert(c); //returns 1
}
func2();
The first code is equal to this:
var a = 123;
function func() {
var a; //Undefined!
alert(a);
a = 1;
alert(a);
}
This explains it pretty well:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/var

how to access function caller context?

I'm trying to understand javascript scopes, and I want to know if in the following example:
// B can access 'context'
var a = function (context) {
b = function () {
console.log(context);
};
b();
};
a('nicccce'); // works!
// C can't access 'context'
var d = function () {
console.log(context);
};
var c = function (context) {
d();
};
c('oh oh'); // breaks
is there a way of accessing 'context' from the 'd' function?
EDIT:
I know I could pass the argument to the d function and thats obviously the sane thing to do, but I wanted to know if there was another way of doing it, maybe using this.callee as this.callee.arguments[0].
You can either
1) pass context into d as you do for c and a. or
2) put context int the lexical scope of d.
Option 2 sounds complicated, but it isn't. That is exactly what you are doing in the case of b. context is "closed-in" to the execution scope of b because the variable is available on the scope of the caller of b (because it is an argument to a).
No, that's not possible and would result in very ugly/unreadable spaghetti code.
Why can't you pass it as an argument to the function? Another (but also ugly) solution would be declaring the variable in a scope where both functions can access it (i.e. in a parent function or global)
In your example, "context" is a variable scoped to function c() and a() (two different variables in two different scopes with the same name).
Judging from how you named the variable "context", I think .call is what you are looking for?
It is worth saying that scope in javaScript is actually very simple once you get block scope out of your mind. Anything appearing between function { ... } is a scope.
In your case if you pass context as an argument in c it will not break:
// C can access 'context'
var d = function () {
console.log(arguments[0]);
};
var c = function (context) {
d(context);
};
c('oh oh'); // doesn't break
And in d you will be able to access it by using argv/args (can't remember exactly)
So something like args[0] or argv[0]
EDIT:
Changed code with arguments
Define a variable that is in the top scope:
(function(){
var global;
var d = function () {
console.log(global);
};
var a = function (local) {
global = local;
b = function () {
console.log(global);
};
b();
};
}())

Categories

Resources