In the below code snippet, i is declared after function f, so how can function f access i's value?
let f;
if (true) {
f = () => {
console.log(i)
}
let i = 1;
}
f();
In the below code snippet, i is declared after function f, so how can function f access i's value?
let f;
if (true) {
f = () => {
console.log(i)
}
let i = 1;
}
f();
i is declared after function f
Ehm, yes, but in the same scope (block).
i
is declared in the same block
as the value of f
(an anonymous function that uses i
), so it is in scope:
f = () => {
console.log(i)
}
// same scope as the definition of the anonymous function:
let i = 1;
Now at the time of declaration, the anonymous function does not need to know what i
is, and if you never declared it, it would just resolve to undefined
when you do f()
.
At the time of execution, i
is already declared and assigned a value. The anonymous function "recalls" this variable because it was declared in it's scope. This is called a closure.
First of the let keyword scope for block of code in your program 'i' is inside of if block so 'i' value scope is inside of if block.
so,if you create 'n' number of function inside of if block it'll access the 'i' value.
please check my example remove the comment in f1() inside console.log(j) and put debugger you'll understand clear.
Here, you'll get error because 'j' is only access for f() means 'j' scope only inside of f(). If you use inside of f() it'll access. Check f2() it's able to access 'j' value.
<script>
debugger
let f,f1,f2;
if (true) {
f = () => {
console.log(i)
let j=11;
f2=()=>{
console.log(j);
}
}
f1=()=>{
console.log(i);
//console.log(j);
}
let i = 1;
}
f();
f1();
f2();
</script>
You are correct that the variables declared by lexical let
declarations may not be accessed without error until after the declaration lexically occurs. (This is in contrast to var
declarations, which make their declared variable accessible and referencible starting from the top of their containing scope, regardless of where the declaration occurs within that scope.)
The variables referenced by name in f
are not accessed until f
is actually called. The JavaScript engine does not ask the question "In what scope is the variable i
and what is its value?" until f
is executed. At the chronological time f
actually is executed, the surrounding block scope has had the variable i
made accessible within it, so f
can use that variable to resolve the identifier i
.
When you refer to i
at execution time, the JavaScript engine looks up the scope chain to find the nearest declared variable named i
. The declaration let i
is an instruction to the JavaScript engine to make available a variable named i
to the current block scope. The fact that the surrounding scope has no accessibl i
at the time f
is defined is immaterial; what matters is that the scope does have a variable i
by the time f
is executed.
Consider this example:
var f;
if(true) {
f = ()=>{ console.log(i) }
try { f(); } catch(e) { console.log(e); }
let i = 1;
try { f(); } catch(e) { console.log(e);}
}
The first call produces an error, because during the execution of f
, no i
has yet been made accessible, while the second execution, after the let i
statement, runs without error.
As Javascript is an interpreted language, it will execute statements one at a time, line by line, without looking at the entire code first (unlike compiled languages). What this means is that your function will not throw an error at the line console.log(i);
before runtime.
At runtime, you are defining and initializing i
before calling the function f
, so by the time f
is called, the value of i
is already known.
Regarding scopes, i
and f
are declared in the same block (not inside a function or anything), therefore f
can access i
fine. No scope issues there.