I have some trouble to understand the Javascript execution context
see below code:
<script >
var global_var;
first();
function first() {
var first_var = 'a';
second();
}
function second() {
var second_var = 'b';
console.log(first_var);
console.log(second_var);
}
console.log('in the outer');
//second();
</script>
Based on my understanding, when first function call the second function, the second function is inside first function's execution context, so, the second can also access first function's properties, here is first_var
But, the actually output in function second display "first_var is not defined"
I am confused, could some one give me some explanation?
Thanks in advance.
Scoping is based in the lexical structure of the code, not the dynamic runtime relationship between functions (the "thread of execution"). The lexical structure is the static organization of the code; the "nesting" of function inside function.
In your case, the "second" function is declared outside of the "first" function, so the local variable in "first" is not visible to the code in "second".
If you were to move the "second" function inside "first":
function first() {
function second() {
var second_var = 'b';
console.log(first_var);
console.log(second_var);
}
var first_var = 'a';
second();
}
then the variable would be visible.
JavaScript has two scopes: global and function. (ES6 will introduce block scope with let and const, but for the sake of discussion, just assume the first two.
What this means is that variables defined in a function are only visible within that function. This has nothing to do with execution context.
So, in your example, first_var is only visible in first, second_var is only visible in second, global_var is visible globally because its not defined in a function.
Execution context comes into play with how this is defined, but that is another question and another topic entirely.
Related
I can't figure out why an unexecuted closure can capture the outer variables.
I do read about some articles about execute context, lexical environment, memory management, but none of these can solve my question:
function foo() {
var a = 1;
return function() {
console.log(a);
}
}
var f = foo() // line 7
// HERE variable a was been captured
f = undefined // line 10
// HEAE variable a was been released
When the engine execute to line7, the foo execution context was created above global execution context, but after line7 the closure was never been execute, so the closure execution context was never been created, so was the lexical environment. foo execution context was been popped up, the variable a will be released.
I can't find what's wrong with my point.
So why and when the variable in closure be captured?
function foo() {
var a = 1;
return function() {
console.log(a);
}
}
Function inside function are known as closure.
When one function has another function inside it, and say top level function has some data like 'a' in this case, then all the inner functions will get access to that data, this will happen only if inner function has some reference about those variables.
Let's say if you have 'b' variable beside 'a' and you are not using it anywhere in inner functions this will be simply ignored by javascript. 'Closure' will not hold this value like 'a'.
This is actually where closure gives devs power.Check out below example -
const test = (num1) => (num2) => console.log(num1*num2);//closure is in action here
var s = test(100)
s(2); // this will give output of 200
Hope this helps.
Thanks.
Here is a discussion on bugs.chromium that is related to your question. As per this , even when the else block never executed , reference to an outer object used in function returned by else block is created and stored in heap. It is never garbage collected. Refer to below discussion :-
https://bugs.chromium.org/p/chromium/issues/detail?id=315190
The key point is lexical scope:
Lexical scope is the scope model used by the JavaScript language, which differs to some other languages which use dynamic scope. Lexical scope is the scope defined at lexing time.
Considering this:
var a = 1
console.log(a)
console.log(b)
var b = 2
console.log(c)
You can get the result:
1
undefinded
ReferenceError: c is not defined
So, you can see how JavaScript handling the variables: all variable are defined at lexing time and assignment at runtime. This is what they called hoisting.
Back to the question: closures capture variables at lexing time in which js engine read your code and defined variable and bind them.
Read more about compilation at: https://v8.dev/blog/background-compilation
How the variable 'str2' is available inside the callback method passed to display method?
str2 should be visible only inside function 'name'.
a = {
display: function (n){
console.log("I am inside display method");
n();
}
}
function name(a,str2)
{
a.display(function (){
console.log(str2);
})
}
name(a, 'ddd');
Variable scoping in Javascript is hierarchical. Lower scopes have access to all variables of all higher scopes. Here's an example:
function outer() {
var foo = 2;
function inner() {
console.log(foo); // 2
}
}
It doesn't matter if a variable is passed as a parameter or if it was defined as a local var.
Yes str should be visible only inside function 'name' yes it is working same you said, in JavaScript function declarations loads before any code is executed, and scope depend on execution context
in your code scope of str2 is inside name() function and you call a.display() within this scope (within scope of name()) that's why str2 available inside display() at the time of execution.
To evaluate name(a, 'ddd'), the compiler will create a new stack frame and place two slots on it, one a, which will be a reference to the global object of the same name, and str2, which will contain the string literal 'ddd'. Then the body will be evaluated.
In the body, to evaluate a.display(function(){...}), the value of a.display will be resolved to the function with parameter n. To evaluate n(function(){...}), a new stack frame will be created with n assigned to the closure that results from evaluating the anonymous callback (a closure being a combination of a pointer to the static scope of the function and the compiler generated code for the function itself). Then the body of the a.display function will be evaluated.
In the body, the console.log will be called with the given string. Then the callback n() will be evaluated. Since n doesn't take any parameters, it will just be evaluated in the topmost stack frame, so when the time comes to evaluate console.log(str2), str will not be found on the current stack frame, so the compiler will follow the scope chain all the way to the frame where we bound 'ddd' to str and a to the function.
That's a pretty long answer to your simple question. I'll try to shorten it later. Also, corrections are welcome, as I'm being very hand-wavy with the evaluation process.
In Javascript the variable declared on a certain scope is available in every inner scope. In this case it's a concept called "closure". This answer might give you good insight about scoping in Javascript: What is the scope of variables in JavaScript?
Hope this simple example can help you understand its usefulness:
function counter () {
var votes = 0;
this.upvote = function() { votes++; }
this.downvote = function() { votes--; }
this.getValue = function() { return votes; }
}
var counter1 = new counter();
counter1.upvote();
console.log(counter1.getValue()) // Prints 1
counter1.upvote();
counter1.upvote();
console.log(counter1.getValue()) // Prints 3
function one() {
function two() {
alert(i);
}
return two;
}
(function() {
var i = 3;
var f = one();
f(); // Uncaught ReferenceError: i is not defined
}());
The articles I've read say that, when a function is called, a new execution context is added on to the stack and the scope chain is created by traversing up the stack. But surely that would result in 3 being alerted in the above code?
How does it work out the scope chain?
The scope chain is determined by the lexical nesting of scopes. The scope can be affected dynamically (via with), but that causes a lot of problems. It's definitely not the case that the current stack of function activations has anything to do with scope.
When you do var i = 3;, you are creating a local variable that exists only in the scope of the immediately-invoked function expression (IIFE).
Any functions that are defined in that scope can access the variable i.
one() (and therefore also two()) was declared outside the scope, so it has no idea what i is. It's looking up its scope chain to window.i, which doesn't exist.
The call stack (as mentioned keeps adding an execution context to the top of the stack when a function is invoked) and lexical scope (which allows access to variables from outer scope) are independent of each other.
Lexical scope depends only on where the function is created not where the function is invoked, so in your example function "two" is created inside function "one", so when variable "i" inside function "two" tries to access "i", it tries to find "i" in its own scope first, since there is no "i" defined it will go out to the scope where the function is created in your case its function "one" (not where the function is invoked in anonymous IIFE below) and it couldn't find variable "i" again inside function "one", now since function "one" is defined inside global scope (the default execution context) JS will try to find the value of "i" inside the global scope which results in "undefined".
In order to access variable "i" you need to move function "two" into anonymous IIFE as shown below, function two has outer lexical scope of function "one" which has an outer lexical scope of anonymous IIFE which has i assigned to 3 which is alerted.
(function () {
var i = 3;
function one() {
function two() {
alert(i); // will alert 3
}
return two;
}
var f = one();
f();
}());
Hope this is clear now :)
The call stack and the execution context stack are not the same. A function call adds a level to the call stack, but execution context stacks are not changed. However, the function that you call has a different execution context stack.
Each function scope has its own execution context stack which is determined by where the function is created, it doesn't inherit the execution context stack from the calling code.
If you nest functions in each other and only call the inner functions, like in the first example on the page, the call stack and the execution context stack will happen to correspond.
Execution stack is what happens on hardware (memory), regardless of whatever high level language is running. The scope chain model is managed by specific interpreter to implement programming language features such as functional programming, which itself is another program independent from the one you've written, the sequence of function call stacks via the interpreter is different from the actual order on physical hardware.
I'm trying to run the same function multiple times at once but if I create a local one with var variablename the sub-functions dont recognize it. And if I make it global, all instances of the Function will overwrite it.
function vladimir(){
var test="hello";
hanspeter();
}
function hanspeter(){
console.log(test);
}
console.log outputs undefined.
You're running into a scoping issue here.
When you declare methods without using var (function <function_name>() {}), those function declarations are moved to the top of the local scope (called function hoisting, if you want to look it up).
If you manually declare you functions, you have to wait until they are both declared before you can use them. This is because the first function won't know about any functions declared under it.
You've also got an issue where variables aren't being scoped. If you have a variable that you declare in one function, it isn't guaranteed to be there in another (since it is a different scope).
If you want to pass these variables around, the easiest way is to pass these into the function parameters, which will be reachable in your other function.
So in your simple example, you could get it to work like this:
var hanspeter = function (test) {
console.log(test);
}
var vladimir = function() {
hanspeter( "hello" );
}
Use function arguments:
function vladimir(){
var test="hello";
hanspeter(test);
}
function hanspeter(arg){
console.log(arg);
}
https://learn.jquery.com/javascript-101/functions/
JavaScript uses lexical scoping - it looks like you're expecting dynamic scoping. Essentially what this means is that a function has access to variables based on where it is declared, not where it is called. For example, the following would work:
function vladimir(){
var test="hello";
function hanspeter(){
console.log(test);
}
hanspeter();
}
Because test exists where hanspeter is declared. But in yours, test exists where hanspeter is called, which does not give it access.
You can also get variables by passing them:
function vladimir(){
var test="hello";
hanspeter(test);
}
function hanspeter(test2){
console.log(test2);
}
I called the argument to hanspeter test2 to show that it is the argument's name that matters, not the name of the variable being passed.
In a comment on another thread I started, someone said this:
#adlwalrus yes. try this: var foo = function bar(){}; console.log(foo); But be aware that bar is only function name (what does it mean I'm not sure exactly myself) and not a reference to it, so you can't call it by doing bar(). And assigning (even named function) is not the same as declaring a function. Hoisting (bumping to top of the scope) only works for declarations, assignment will stay in place. – valentinas 6 hours ago
What purpose does a function name serve if you can't call it with bar()?
For the function to call itself.
var x = function y(val){
if (val){
console.log(val);
y(val-1);
}
};
x(5);
> 3
> 2
> 1
y(3);
> ReferenceError: y is not defined
You're referring to a named function expression. The spec requires that the name of such functions only be available within the scope of the new function. Spec quote:
The Identifier in a FunctionExpression can be referenced from inside
the FunctionExpression's FunctionBody to allow the function to call
itself recursively. However, unlike in a FunctionDeclaration, the
Identifier in a FunctionExpression cannot be referenced from and does
not affect the scope enclosing the FunctionExpression.
On the other hand, the result of that expression is a reference to the new function, which can be saved and referenced anywhere.
Lots of details here:
http://kangax.github.com/nfe/#named-expr
I'd read the whole thing.
As for benefits, another is that it makes them easier to identify in a debugger.
There are two ways to create a function in JavaScript, a "function declaration" and a "function expression." I believe it was Doug Crockford who explained it best when he pointed out that unless "function" is the very first set of characters on a given line, you're performing a function expression (not a declaration).
Function declarations are finicky creatures. You'll recognize them when you see them. They look like this:
function foo() { /* ... */ }
They're always given a name (it's requited) and the name is locally scoped to the lexical context under which the function is declared. So if you perform a function declaration in the global context, then the function can be referenced via it's name globally. If you do it within a function, the function's name can be referenced only within that function and any functions declared within that function.
I think the most important aspect of this method of declaring a function (one that is rarely commented on) is that the function initialization gets hoisted to the top of the current lexical context. Therefore, you should never, ever use a function declaration within a conditional, such as this:
//DON'T DO THIS!
if (x) {
function foo() { return 1; }
} else {
function foo() { return 2; }
}
foo(); //will always be 2, regardless of the value of x.
A function expression is slightly different. Often, they're directly assigned to a variable, like so:
var foo = function() { /* ... */ };
This is nearly identical to the function declaration above except that the initialization is not hoisted. So you can do the following:
var foo;
if (x) {
foo = function() { return 1; };
} else {
foo = function() { return 2; };
}
foo(); //will be 1 or 2, depending on the truthy-ness of x.
So, back to the original question. Function expressions can also have a name, though it's not required and it's not scoped to the context in which the function is declared (as with function declarations). Instead, it gets scoped to the function's own lexical context. This is very useful in some cases. My personal favorite is this pattern:
(function foo() {
//Do something.
setTimeout(foo, 1000);
}());
foo; //undefined
Because of the parenthesis before the word "function", this is a function expression and the name is scoped internally only. But that's okay, because we only need to call it internally (via setTimeout()). The result is that the function will execute once immediately, then will re-execute every second or so after it's finishes execution. This is safer than using setInterval() because it will wait until it's done executing before rescheduling itself, preventing overlaps that could cause missed executions and/or "domination" of the JavaScript thread.
Essentially, the use of a named function expression is limited, but when you need it, it's very powerful.