Why is execution context needed for JS - javascript

I am new to JS and was learning the role of execution context in JS and asked myself what is the benefit of execution context in JS and why JS is run via execution context. The second question is as we know there are global and functional execution contexts and each context has two phases creation phase and execution phase. So, why we need these two phases? what is the point of having them.

The concept of an "execution context" provides a way of reasoning about what happens when the global environment is created and executed, or when a function is called. It's a conceptual container for the local variables (globals, in the case of the global environment), parameters (for functions), etc. A JavaScript engine can be written without literally having any object it calls an "execution context," as long as it implements the language in keeping with the spec's defined execution context behavior.
One thing that the execution context helps explain is the behavior of closures. A function created within a given execution context has (conceptually) a reference to that context, even after the function call related to the context has completed:
function foo(answer) {
return function say() {
console.log(answer);
};
}
const s = foo(42);
s(); // 42
That works because the function say has a reference to the context of the call to foo that created it (well, more specifically to the thing called its "lexical environment"). That lexical environment continues to exist after foo returns because something still has a reference to it (say). So the call to say afterward works.
The reason for having two phases is to allow use of identifiers before their declaration. This is primarily useful for function declarations:
main();
function main() {
console.log("Worked");
}
The first phase processes the function declarations (and var statements), and then the step-by-step phase runs the code. Without the first phase, the code above would fail as of main(); because main would be undeclared. Of course, with the simple example above, you could just move the main(); call to after the function declaration, but more complicated cases become harder to solve in that way. Languages that didn't have two phases (early C, for instance) had to provide a mechanism for "forward declaring" things that would be defined later. Having two phases means JavaScript doesn't have to have those. (To be fair, C also differs from JavaScript in that it needs to know what all identifiers refer to during compilation, even if the identifiers are in code within functions. So it needed forward declarations just to allow foo and bar to call one another. JavaScript doesn't check the identifiers used within functions until the function is called, so some of the reasons for forward declarations in C wouldn't come up in JavaScript even if it didn't have two phases.)
It wasn't perfectly successful. Having var statements initialize the variables they declare with undefined before the var statement is reached in the code was often the source of bugs and confusion:
console.log(answer); // undefined
var answer = 42;
It's easy for people to be confused by the fact that half of the var answer = 42; was done early (the var answer part), but the other half (answer = 42;) isn't done until later when that statement is reached.
That's why let and const create, but don't initialize, their variables during that first phase. You can use a variable above where it's declared, but only in code that runs after the initialization:
function foo() {
console.log(answer);
}
// foo(); <== Would fail, `answer` isn't initialized yet
let answer = 42;
foo(); // Works, logs 42

Related

Javascript Hoisting - How are we Accessing Certain Variables?

I have two questions about hoisting:
The way function declarations are hoisted is that they go to the very top, even above variable declarations, to my understanding.
If we have this code:
function fn() {
callback();
}
function callback() {
console.log('why does this show');
}
I don't understand how this works, since both functions are hoisted to the top (which effectively produces the same code that already exists). But callback is still created below fn, and I don't see why we can access it in fn. My guess is it has something to do with the top level objects being able to access each other regardless of lexical position.
Similarly:
var a = 10;
function fn() {
console.log(a);
}
fn();
How does this work? Because the way I understand hoisting makes it seem like the function should be hoisted even above var a, which makes it seem like variables should always be inaccessible in functions.
We can go down the rabbit hole with this but I want to try to give a brief explanation on how your examples work.
Whenever the JavaScript engine creates an execution context (also known as calling stack) whether through functions or code in the global scope it creates an lexical environment. Which is a data structure that holds a collection of name/value pairs about variables and functions in it's own scope or from it's parent scope by using a reference.
About your first example. Both functions get added to the global execution context. If you call fn() in your first example initially. It will then add callback() to the call stack of fn() and execute it accordingly. So, the order of your functions don't really matter in this case.
You're second example is a different case. The execution context knowns you are referring to the global variable and therefor adding a reference to the lexical environment and that makes it able to use the variable inside fn().
This can be quite hard to get a grasp of. There are a ton of resources related to hoisting, scopes, lexical environments and execution contexts so be sure to check those out. :)
This is because how our Javascript Engine parse and compile the code.
I'm not an expert but V8 (The Chorme Engine for JS) in the first file get all the variables and functions names and store all the function references. So, you can "use" a function before "declare" because JS know where the function is.
Some languages, even C++ you could do that and is a nice feature :)

Should closures be used to structure code even if they are not depended on lexical scope? How about redeclaration inside loops?

2 questions:
Closures have the advantage of being able to access the outer scopes and therefore are a great tool in our toolbox.
Is it frowned upon just using them to structure the program if scoping is not needed?.
foo = () => {
closure = (_)=> {
...
}
if(...){
closure(bar);
}else{
closure(baz);
}
}
In this case the function does not depend on the scope and could
be moved one level higher without change in functionality. Semantically it makes sense to place it there since it will only be used inside foo.
How do closures behave if they are declared inside loops? Does redeclaration hurt performance?`
foo.forEach( x => {
closure = () => ...
})
Is it frowned upon just using them to structure the program if scoping is not needed?
There is no one way to write JavaScript code (or any other code). This part of the question calls for opinion, which is off-topic for SO. :-)
There are a couple of objective observations that can be made about doing that:
It keeps the functions private, they can only be used in the function they're created in (assuming you don't return them out of it or assign them to variables declared in an outer scope). That could be argued as being good (for encapsulation) and as bad (limited reuse).
Modules probably reduce the desire to do this a bit (though not entirely).
How do closures behave if they are declared inside loops?
A couple of things I need to call out about your example relative to the question you've asked there:
You haven't declared a function at all. You've created one, via a function expression, but you haven't declared one. (This matters to the answer; we'll come back to it in a moment.)
Your example doesn't create a function in a loop, it creates it inside another function — forEach's callback. That function is called several times, but it isn't a loop per se.
This code creates a function in a loop:
for (const value of something) {
closure = () => {
// ...
};
}
It works just like creating a function anywhere else: A new function object is created each time, closing over the environment where it was created (in this case, the environment for each iteration of the loop). This can be handy if it's using something specific to the loop iteration (like value above).
Declaring a function in a loop looks like this:
for (const value of something) {
function foo() {
// ...
}
}
Never do that in loose-mode code, only do it in strict mode (or better yet, avoid doing it entirely). The loose-mode semantics for it aren't pretty because it wasn't specified behavior for a long time (but was an "allowed extension") and different implementations handled it in different ways. When TC39 specified the behavior, they could only specify a subset of situations that happened to be handled the same way across all major implementations.
The strict mode semantics for it are fairly reasonable: A new function object is created every time and the function's identifier exists only in the environment of the loop iteration. Like all function declarations, it's hoisted (to the top of the block, not the scope enclosing the loop):
"use strict";
const something = [1, 2, 3];
console.log(typeof foo); // Doesn't exist here
for (const value of something) {
foo();
function foo() {
console.log(value);
}
}
console.log(typeof foo); // Doesn't exist here
Does redeclaration hurt performance?
Not really. The JavaScript engine only has to parse the code once, creating the bytecode or machine code for the function, and then can reuse that bytecode or machine code when creating each of the function objects and attaching them to the environment they close over. Modern engines are very good at that. If you're creating millions of temporary objects, that might cause memory churn, but only worry about it if and when you have a performance problem that you've traced to a place where you've done it.

Reasons to or not to declare functions in an if-statement

I need some confirmations on what’s happening behind the screen.
There’s an article in MDN that said that we shouldn’t declare functions in a block-level, such as, inside an if-statement. Because it’s inconsistent throughout browsers and anything to do with pre-ES2015 (or pre-ES6).
The function inside the if-statement will not be created unless the condition is true.
I was wondering, IF the condition is true, let’s say 5 minutes later after JavaScript is loaded and set synchronously, will it create the function? Does it still have memory of the code in order to create the function, or is it dumped in unused code and all?
I would like to know whether the function still exists even after the if-statement is completed. Is it accessible? How long is it accessible? Is it accessible until the if-condition is false? Does the result differ from ES6 and pre-ES6? I’ve heard there’s no scope pre-ES6 in if-statements.
e.g.
if (condition) {
function foo() {console.log(“hello world”);
}
}
I was confused after reading an article in MDN on ‘Functions’ under ‘block-level functions in non-strict code’: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
IF the condition is true, let’s say 5 minutes later after JavaScript is loaded and set synchronously, will it create the function?
The function will be created as soon as the if runs, immediately.
Does it still have memory of the code in order to create the function, or is it dumped in unused code and all?
I would like to know whether the function still exists even after the if-statement is completed. Is it accessible? How long is it accessible?
This behavior will be the same regardless of if the function is declared in an if block or not: if nothing can possibly reference the function in the future (for example, if the block ends and nothing inside the block has a reference to the function), it will eventually be garbage collected. The function may still "exist" in memory for a time until the GC runs.
For example, it should be clear that the following function should always continue to exist, at least until you reload the page:
// IIFE, to get off the top level
(() => {
if (true) {
function foo() {
console.log('clicked');
}
window.addEventListener('click', foo);
}
})();
This is because the addEventListener has been passed a reference to the function.
But the following foo function will get GC'd (maybe a second or few after the page is loaded - it depends on the underlying engine, and isn't visible to Javascript):
// IIFE, to get off the top level
(() => {
if (true) {
function foo() {
console.log('clicked');
}
}
})();
If nothing has saved a reference to the function by the time the block that scopes the variable has finished, the function will not be accessible anywhere, and will be GCd.
The rest of the question looks to be essentially the same as: "where can the function be referenced", which is best described in Bergi's answer here. It's a bit complicated, and the behavior differs depending on whether you're using strict mode, the ES version of the environment, and the environment itself (implementations do not always conform to the specification).
For predictable, easy-to-read code, probably best to simply never use function declarations in non-function blocks; only use function declarations when directly inside function blocks.
(Note that function expressions, where the function is used as a value and passed to something or immediately invoked or explicitly assigned to a variable, are not the same as function declarations - function expressions are fine, it's just the weird behavior of function declarations that's problematic. Also note, per comment, that a "function declaration" is sometimes called "function statement".)

Does hoisting takes place at once for the full code or by nested-function-levels

Hy guys. I dont understand something regarding the hoisting and it can be it is my bad, but I didnt find any answer, neather here nor on google, thatswhy I ask, thanks for reading.
So I dont understand, As the javascript engine gets my code below and starts to scan through,
will be the whole code with all functions and nested functions scanned threw, until to the very last scope?
And the creation phase of all function will take place for the first scan (or with others words will the full code be scanned just once and prepared everything for each functions)?
/* Global execution context*/
function myFirst(){ /*Scanner meets this code and hoists it*/
var A = "12"
return function myFirstB(){ /*As the scanner arrived here and
scanns threw this function during the parents hoisting period ( or just before the global contexts execution phase) will it be hoisted as well, that it gets [[Scopes]] property? So that when I call it in the last line as a closure, it can remember on, that variable "A" is in its outer-environment?*/
console.log(A)
} //myFirstB()
} // myFirst()
function mySecond(){
alert("one")
}
var myClosure = myFirst();
myClosure(); /*before beeing called does this function have already [[Scopes]] property/scope-chain?*/
Or the hoisting happens nest-level by nest-level? So I mean at first those functions will be hoisted which are defined in the global context?
and then as one of those functions gets invoked and its execution-contexts execution phase starts, will be its nested functions hoisted?
I am investigating this, because I dont really udnerstand, how a nested function remembers on, in which lexical environment/function has it been defined, if it wasnt already at least hoisted, that it has a [[Scopes]] property, which preserves its scope chain
The probelm is all the articles I saw until now and even the ecmascript 6 documentation says only, that the hoisting happens, if the scanner meets a function definitiona and then the scope property will be created with the scope chain and variable object the arguments object and the "this" keyword, but I didnt find any material which would talk about, if the nested functions (which are preserved in the variable object, coupled there with a reference to their function body in the memory) will be at least hoisted as well (at the same time, their parent function is hoisted) and soo they get a scope chain to remember on their outer environment, if they are called outside from there outer-environment
Thanks a lot guys for reading threw my tonns of words, if you can answer it or if you have an article which talks about this aspect as well of hoisting, I would really appriciate
I think you are confused because you tangled too many things. You will need to distinguish three things:
what the parser does
what happens when a scope is created
what happens when code is run
The parser does indeed scan through the whole code. If there was a syntax error anywhere, none of the code would be run. It does parse the whole code into a (nested) structure that is suitable for execution later. This might be an abstract syntax tree or executable byte code, or anything in between - that's an implementation detail.
Before a chunk of code is run, like in the global scope or a block scope or a function scope, the context for that execution has to be created and initialised first. It does get a parent scope reference (e.g. the scope surrounding a block or the scope a closure was defined in), a this value, and a new variable environment in which the variables of this scope are created. Here is where all the variable names declared in the scope (e.g. function parameters, var and function and let and const and class declarations etc) are used to instantiate a new variable.
When the code chunk is executed statement for statement and expression for expression, the variables already exist. This is when the values are created and assigned to the variables. When a function is defined, it does become a closure by referencing the current scope.
The term "hoisting" is giving the wrong impression. No source code is moved around. How an implementation achieves the specified behaviour is not restricted. It might be that the parser creates byte code that has the creation of the variables at the top of each scope. It might be that in the initialisation phase of a scope it scans the AST for declarations every time. It most likely is a mix of those in the form of a just-in-time compiler, which creates the byte code only when the function is called for the first time.
Regarding your question about nested functions, remember that the inner function is re-created every time the outer function is called. It is only "hoisted" to the top of its scope, not outside of the outer function, and will be redefined on every run of the code.
Let me explain to you step by step.
Step 1 (by parser): Scans the whole code (all levels of nesting) to create an AST (abstract syntax tree) and to checks for syntax errors.
Step 2 (by JS engine): Hoists code belonging to the current level only. Then executes current level code. This code may have nested code.
Step 3 (by JS engine): Does Step 2 for nested code.
This process repeats, until all code is executed, for all levels.
PS: Some help taken from this answer.

What is the scope of a function in Javascript/ECMAScript?

Today I had a discussion with a colleague about nested functions in Javascript:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
In this example, trials point out that b is not reachable outside the body of a, much like c is. However, d is - after executing a(). Looking for the exact definition of this behaviour in the ECMAScript v.3 standard , I didn't find the exact wording I was looking for; what Sec.13 p.71 does not say, is which object the function object created by the function declaration statement is to be bound to. Am I missing something?
This is static scoping. Statements within a function are scoped within that function.
Javascript has a quirky behavior, however, which is that without the var keyword, you've implied a global variable. That's what you're seeing in your test. Your "d" variable is available because it is an implied global, despite being written within the body of a function.
Also, to answer the second part of your question: A function exists in whatever scope it is declared, just like a variable.
Sidenote:
You probably don't want global variables, especially not implied ones. It's recommended that you always use the var keyword, to prevent confusion and to keep everything clean.
Sidenote:
The ECMA Standard isn't probably the most helpful place to find answers about Javascript, although it certainly isn't a bad resource. Remember that javascript in your browser is just an implementation of that standard, so the standards document will be giving you the rules that were (mostly) followed by the implementors when the javascript engine was being built. It can't offer specific information about the implementations you care about, namely the major browsers. There are a couple of books in particular which will give you very direct information about how the javascript implementations in the major browsers behave. To illustrate the difference, I'll include excerpts below from both the ECMAScript specification, and a book on Javascript. I think you'll agree that the book gives a more direct answer.
Here's from the ECMAScript Language Specification:
10.2 Entering An Execution Context
Every function and constructor call
enters a new execution context, even
if a function is calling itself
recursively. Every return exits an
execution context. A thrown exception,
if not caught, may also exit one or
more execution contexts.
When control
enters an execution context, the scope
chain is created and initialised,
variable instantiation is performed,
and the this value is determined.
The
initialisation of the scope chain,
variable instantiation, and the
determination of the this value depend
on the type of code being entered.
Here's from O'Reilly's Javascript: The Definitive Guide (5th Edition):
8.8.1 Lexical Scoping
Functions in JavaScript are lexically
rather than dynamically scoped. This
means that they run in the scope in
which they are defined, not the scope
from which they are executed. When a
function is defined, the current scope
chain is saved and becomes part of
the internal state of the function.
...
Highly recommended for covering these kinds of questions is Douglas Crockford's book:
JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript, The Good Parts, also from O'Reilly.
As I understand it, these are equivalent as far as scoping is concerned:
function a() { ... }
and
var a = function() { ... }
It seems important to note that while d is being created as a "global", it is in reality being created as a property of the window object. This means that you could inadvertently be overwriting something that already exists on the window object or your variable might actually fail to be created at all. So:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
But you cannot do:
function a() {
document = 'something';
}
because you cannot overwrite the window.document object.
For all practical purposes you can imaging that all of your code is running in a giant with(window) block.
Javascript has two scopes. Global, and functional. If you declare a variable inside a function using the "var" keyword, it will be local to that function, and any inner functions. If you declare a variable outside of a function, it has global scope.
Finally, if you omit the var keyword when first declaring a variable, javascript assumes you wanted a global variable, no matter where you declare it.
So, you're calling function a, and function a is declaring a global variable d.
...
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
without being preceded by var, d is global. Do this to made d private:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}

Categories