Javascript - outer reference of a function shows "not defined" - javascript

i have the following code:
function log(a) {
var b = 5;
a();
}
log(function(){
console.log(b);
});
When that anon function is executed at function log, I am getting "b is not defined". Well, It seems like that anon's outer environment reference isn't log's, as If it wasn't created inside of it so therefore it can't find that var. so where is it being created? on the global level? My initial thought was that those parentheses make the anon function created inside of log's.

Every time you call a function, assuming that you do not declare global variables (you didn't declared any), the scope is created for that function and what goes in that scope is determined not by where the function was called but by where it was defined. You can see that where you defined the anonymous function (in the call to log), the variable b is not in that scope that is why it's not available.
Let's rewrite your code:
function log(a) {
var b = 5;
a();
}
function logger() {
console.log(b);
}
log(logger);
You can see that your code and mine are doing the same thing, the only difference is that mine code doesn't have an anon function. They do not share common variables in their scopes.
Now check this out:
var b = 5;
function log(a) {
a();
}
function logger() {
console.log(b);
}
log(logger);
Now both log and logger share a common variable b in their scopes (log is not using b so if you check it in a debugger it will be undefined). As I say you don't determine scope by where function was called but by where and how it was declared.

In JavaScript scopes exists within functions. So your b variable is visible only within its scope - the anonymous function. If you want it to be visible outside the function then you can assign the variable to the global scope.
function log(a) {
window.b = 5;
a();
}
log(function(){
console.log(b);
});

Related

JavaScript Scope: Global Variable Confusion

I am having trouble understanding why the following code prints 1 and not 10. I thought that console.log would print 10 because if a variable is not declared within a function it is part of the global scope.
If I remove the line, function a(){}, the console.log statement prints 10. Can someone please explain why the presence of this line affects the value of a.
Additionally, if this question can be refined I would appreciate any suggestions
function b() {
a = 10;
return;
function a(){}
}
var a = 1;
b();
console.log(a);
Just add console.log(a); to your function and you will realize that 'a' is a function that has local scope, which means, it inside function b() and can't really be called from outside. Hence, the value of a remains as 1, as nothing really affects it.
function b() {
console.log(a);
a = 10;
return;
function a(){}
}
var a = 1;
b();
console.log(a);
Function declarations create local variables, and all declared variables are hoisted to the top of their containing function scope. Thus, you have something equivalent to:
function b() {
function a(){}
a = 10;
return;
}
which is in turn roughly equivalent to
function b() {
var a = function(){}
a = 10;
return;
}
As you can see in this form, it's clear that a is a local variable, so a = 10 assigns a value to the local a, not the global a.
Because both function declarations and variables are treated similarly under the hood.
When a function is called, its contents are first parsed to configure the stack frame ready for its execution.
As part of this process, function declarations and variables are inserted as identifier/value pairs into the same data structure (Environment Record inside the Lexical Environment) inside the stack frame (Execution Context) created when a function is called.
So by declaring a function a inside b, you create an identifier named "a" in the Environment Record created for the call to b, shadowing a in the outer context.
So a in the outer context remains 1.

Why can't I access this particular variable when referencing its outer environment?

I'm learning about lexical scope and execution contexts in JS and came across a question.
My understanding of the keyword this may be limited, but I see that it references all variables in any function's current execution context.
Consider this example:
function b(){
console.log(this);
}
var myVar = 1;
b();
Here, I'll get a console log to myVar which will be assigned to the value 1.
Now for this example:
function a(){
function b(){
console.log(this);
}
var myVar = 2;
b();
}
var myVar = 100;
a();
When function b is called, I see a reference to myVar, which is assigned to 100. Why isn't there a reference to myVar as assigned to 2?
Doesn't 'this' refer to the current function's lexical environment? In this case, function b is enclosed in function a and not the global environment.
Your understanding of this is completely wrong.
The value of this depends (usually) on how the function was called. (See How does the “this” keyword work? for details).
If you are:
in a browser
your JS isn't running in strict mode (which it should be)
the function is called with no explicit context
… then this will be the window object.
Normally, when a variable is declared, it exists only in the scope in which it was declared. It is not a property of any object.
There is one exception:
When a variable is declared in the global scope (i.e. outside of any function or without let or var inside a function) then it also becomes a property of the window object.
The effect you are seeing is the combination of those two things.
b(); has no context, so this is window. var myVar = 100; is outside of any function, so is a global and thus a property of window.

Scope chain in Javascript and calling nested function within the global scope

Here is the example I want to be enlighten on (Something that doesn't actually works).
var myVar = 2;
function a(){
var myVar = 2;
function b(){
console.log(myVar);
}
};
a();
b();
This will output in the console: Uncaught ReferenceError: b is not defined.
As you can see I have a function named a with a nested function called b.
At first I thought I could invoke b outside a and get it working normally.
I thought that would work because at first I call the a function.
By doing that I had in mind the fact that the a function would be put on the execution stack and during its creation phase the b function defined inside would be set in the memory.
As this is in memory I thought I could then execute this outside the function. Which obviously doesn't work.
So my conclusion is the b function is indeed set into memory during the creation phase of the a function but once the a function has finished to execute, once it's popped of the execution stack, the b function gets popped off the memory at the same time.
Thus calling it (I mean the b function) within the global scope is impossible.
Am I right on this ?
You are complicating things unnecessarily by speaking about execution stacks, creation phases and such.
The explanation is very simple: you cannot call b because the spec says that b is out of scope at the site where you are trying to call it. That is all, end of story.
Your example would actually work if converted to PHP, which makes me think that perhaps this is where you got the idea from. But JS and PHP are different languages and the (IMO ridiculous) manner that PHP treats nested functions does not transfer over.
If you want to call b outside of a, you need to create a reference to it outside of a:
var myVar = 2;
function a(){
var myVar = 2;
function b(){
console.log(myVar);
}
return b;
};
var b = a();
b();
This however won't cause b to print the global myVar. It will still have access to the myVar inside the closure scope of a.

Global variable override with a local one

The following test is a success, and prints 1 and 1:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "1"
}
test1();
test2();
And the following test fails, because a local variable overrides the previously created global one:
function test1() {
a = 1;
var a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();
Why does the second example remove the global variable permanently? What purpose/logic does such functionality serve in JavaScript?
EDITED: For those who marked it as a duplicate of Strange Behavior on Global and Local Variable in JavaScript
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable. But in our case the function first creates a global variable, and then deletes it completely/globally.
However, it is probably related, as we can see in the following test:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "undefined"
var a = 2;
}
function test3() {
console.log(a); // prints "1"
}
test1();
test2();
test3();
In your second case, no global variable named a ever exists.
a = 1 generally does not create a global variable. The statement a = 1 stores the value 1 in a variable called a. If the variable environment of any containing local scope has a variable called a, the nearest scope with an a variable will have that variable set to 1.
As a special case, if a variable called a does not exist in any containing scope (and if you are not in strict mode), then the JavaScript engine will create a global variable called a.
In your second case, var a creates an a variable in the local scope. Due to hoisting, that modification to the scope's variable environment happens before any code runs. Thus, by the time a = 1 is executed, that local scope does have a variable called a, so that local variable is used.
In your third case, test2 logs the local variable a (created by the var a). At the time the log call is made, the local a has not yet been assigned a value.
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable.
Hoisting simply means that all var declarations are treated as if they happen at the top of their containing function. It has nothing to do (directly) with overriding variable visibility.
Note that declarations with an assignment will have only the declaration hoisted, not the assignment. The assignment stays in place wherever it is in the function.
Javascript moves variable declarations to the top. So in this example the compiler reads you code as:
function test1() {
var a;
a = 1;
a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();

Trying to figure out how scope works

I'm trying to learn JS on codeacademy and I can't understand/get past this thing. Can someone please provide an answer and also an explanation of why is it so? Would deeply appreciate.
// This function tries to set foo to be the
// value specified.
function setFoo(val) {
// foo is declared in a function. It is not
// accessible outside of the function.
var foo = val;
}
setFoo(10);
// Now that we are outside the function, foo is
// not defined and the program will crash! Fix this
// by moving the declaration of foo outside of the
// function. Make sure that setFoo will still update
// the value of foo.
alert(foo);
You can see scope as a term meaning what variables you can reach at a specific "level" in the code. In JavaScript, these "levels" are defined by functions. Each function introduces a new level.
For example, take this sample code:
var a;
// you can access a at this level
function function1() {
var b;
// you can access a, b at this level
function function2() {
var c;
// you can access a, b, c at this level
}
}
So in your case, you should declare var foo; outside the function, preferably above it. Then you can set it inside setFoo with foo = val;. foo then refers to the one you declared in the level above setFoo.
foo is accessible both in setFoo and in the alert call that way; compare it with the above sample code (function1 is setFoo, a is foo and the alert call is in the top-most level. function2, b and c are not used in your case.).
// Create globale variable
// (You should not use globale variables!)
var foo;
// set value
function setFoo(val) {
foo = val;
}
setFoo(10);
// show value
alert(foo);
Just declare foo outside any function then it will be global:
var foo = null;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo);
Try it !
When you declare a variable in Javascript it is only visible to code that is in the same function as it is declared, or a function inernal to that function. Because foo is originally declared in the SetFoo function nothing outside of SetFoo is able to see it, so the call to alert fails as foo does not exist in the gloabl scope.
As the comments suggest, moving the declaration of foo out of the function and into the global scope (which you can think of as a catch-all function that contains everything) would allow you to use foo when calling alert.
var foo;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo); // No longer crashes
Every function in Javascript has it's own scope. That means that every variable you define there with the var keyword, will only be available within that function. That means that when you call setFoo(10), you create the variable foo, give it a value of five, after which it is immediately destroyed because it went out of scope.
There are multiple ways to solve this problem. The first would be to remove the var keyword. This would put foo in the global scope, which means that it's available everywhere. However, this is discouraged, you want to keep the global scope as uncluttered as possible, so that if you have javascript code provided by multiple people on the same page, they can't overwrite other people's variables. Another way to do it would be this:
function setFoo(val){
var foo = val;
alertfoo = function(){
alert(foo)
}
}
In this example, the only thing you're putting in the global scope is the alertfoo function, because you want that to be available everywhere. The alertfoo function is defined inside the setFoo function, this means that although foo should have gone out of scope after setfoo has been executed, it is kept in memory, because alertfoo has access to it.
This makes for some nice tricks. For example, let's say you're making a javascript library that will be included on other people's pages, you'll want to create a scope inside of which you can define variables, without polluting the global scope. The most common way to do this, is by declairing a self-executing function. This is a function which is executed immediately after being defined, it looks like this:
(function(){
//set variables you want to be global in your own code
var mainpage = document.getElementById('main');
//define functions you want to make available to other people in a way that puts them in the global scope
setMainElement = function(newmain){mainpage = newmain;}
})();
You can make this even better by making only one object global, and provide your interfae through the methods of that object, this way, you create a namespace with all the functions that your library contains. The next example uses an object literal to do this. In javascript, you can create an object by putting key/value pairs petween curly braces. the key/value pairs are properties of the object. for example:
(function(){
var privatevar = 10,otherprivate=20;
publicInterface = {
'addToPrivate': function(x){privatevar+=x;},
'getPrivate': function(){return private}
};
})();
Original code:
function setFoo(val) {
var foo = val;
}
setFoo(10);
alert(foo); // Crash!
Their advice to fix the crash:
Fix this by moving the declaration of foo outside of the function
I'm guessing you're confused as to what they mean by "outside of the function".
Try this edited code:
var foo = 5; // "var" declares the variable to be in this outer scope
function setFoo(val) {
foo = val; // but we can still access it in this inner scope...
}
setFoo(10);
alert(foo); // Displays a dialog box that says "10"
Variables defined in the function is valid only in the function
function setFoo(val) {
foo = val;
}
In JavaScript, new scopes are only created by functions

Categories

Resources