I understand them through examples. :)
First, lexical scope (also called static scope), in C-like syntax:
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
}
Every inner level can access its outer levels.
There is another way, called dynamic scope used by the first implementation of Lisp, again in a C-like syntax:
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}
Here fun can either access x in dummy1 or dummy2, or any x in any function that call fun with x declared in it.
dummy1();
will print 5,
dummy2();
will print 10.
The first one is called static because it can be deduced at compile-time, and the second is called dynamic because the outer scope is dynamic and depends on the chain call of the functions.
I find static scoping easier for the eye. Most languages went this way eventually, even Lisp (can do both, right?). Dynamic scoping is like passing references of all variables to the called function.
As an example of why the compiler can not deduce the outer dynamic scope of a function, consider our last example. If we write something like this:
if(/* some condition */)
dummy1();
else
dummy2();
The call chain depends on a run time condition. If it is true, then the call chain looks like:
dummy1 --> fun()
If the condition is false:
dummy2 --> fun()
The outer scope of fun in both cases is the caller plus the caller of the caller and so on.
Just to mention that the C language does not allow nested functions nor dynamic scoping.
Answer from Khaled Alshaya on Stack Overflowjavascript - What is lexical scope? - Stack Overflow
Lexical Scope in JavaScript - Stack Overflow
javascript - what is the lexical scope of an object? - Stack Overflow
What is lexical scope in JavaScript?
Videos
I understand them through examples. :)
First, lexical scope (also called static scope), in C-like syntax:
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
}
Every inner level can access its outer levels.
There is another way, called dynamic scope used by the first implementation of Lisp, again in a C-like syntax:
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}
Here fun can either access x in dummy1 or dummy2, or any x in any function that call fun with x declared in it.
dummy1();
will print 5,
dummy2();
will print 10.
The first one is called static because it can be deduced at compile-time, and the second is called dynamic because the outer scope is dynamic and depends on the chain call of the functions.
I find static scoping easier for the eye. Most languages went this way eventually, even Lisp (can do both, right?). Dynamic scoping is like passing references of all variables to the called function.
As an example of why the compiler can not deduce the outer dynamic scope of a function, consider our last example. If we write something like this:
if(/* some condition */)
dummy1();
else
dummy2();
The call chain depends on a run time condition. If it is true, then the call chain looks like:
dummy1 --> fun()
If the condition is false:
dummy2 --> fun()
The outer scope of fun in both cases is the caller plus the caller of the caller and so on.
Just to mention that the C language does not allow nested functions nor dynamic scoping.
Lets try the shortest possible definition:
Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.
That is all there is to it!
To understand the lexical scope you need to have a basic understanding of the scope. In javascript, we have classified scope in three types
- Function scope
- Block Scope
- Lexical Scope
Function Scope -> The variables defined inside the function are considered in function scope.the var keyword is used to define the variable in the function scope.
Block scope -> The variables defined in the area within if,switch condition,for,and while loops. whenever you see '{}' curly braces, its a block. In Es6 const and let keywords allow developers to declare a variable in the block scope. which means those variables exist only within the corresponding block.
Copy function animal(){
if(true){
var animal1 = "cat";
const animal2 = "dog";
let animal3 = "rat";
}
console.log(animal1);
console,log(animal2); //animal2 is not defiend
console,log(animal3); //animal3 is not defiend
}
animal();
result
cat
animal2 is not defined
animal3 is not defined
Lexical scope-> In 1 line I want to say "children scope have access to the variable in parent scope" `
Copyvar outerFunction = function()
{
if(true){
var x = 5;
const y = 10;
}
var innerFunction = function(){
if(true){
alert(x);
//alert(y); //y is not defiend on line 13
}
}
innerFunction();
}
outerFunction();
//console.log(x); // x is not defiend on line 20
`. The scope of a variable is defined by their position in the source code. In order to resolve variable javascript starts at the innermost scope and searches outward until it finds the variable it was looking for. lexical scoping is nice because we can easily figure out what the value of a variable will be by looking at the code; whereas in dynamic scoping the meaning of a variable can change at runtime by making it more difficult
Your understanding of how scope works for standard functions (including closures inside closures) is correct, but for arrow functions this statement is wrong:
"this" is bound to obj because of the lexical scoping of "this" with arrow functions.
With an arrow function this within the function is the same as whatever this was outside the function when it was created. It is not bound to obj in your example, but instead to whatever it was already bound to where that obj is being created.
It is useful in a situation such as:
Copythis.values.filter( x => x < this.max );
Inside that arrow function this is the same as it was outside the function. With a regular function it might have been written like this:
Copythis.values.filter( function ( x ) { return x < this.max }.bind( this ) );
or:
Copyvar self = this;
this.values.filter( function ( x ) { return x < self.max } );
I use "scope" instead of "LE" here, as the former is more common in JavaScript learning resources.
Functions have their own scope; objects do not. So while (1) the scope of stacy is indeed the global scope, (2) the code of sayName runs in its own scope, for which the parent scope is the global scope. this.name works because non-arrow functions have an additional binding this added to their scope, but name doesn't work because the object isn't a scope, it's just a data structure with a 'name' property. stacy.name would work, and you could declare a name variable with another var or let statement that would work in either scope.
Example 1:
var x = 20;
function foo() {
console.log(x);
console.log(this.x);
}
foo();
In the above example, if we do either console.log(x) or console.log(this.x), it will print the same value. Why so? Because the x is available as a variable to the function foo in its parent scope, it is also available as a property in the global object. The parent object for foo is the global object as it is defined and the function created using the function keyword has a bound context of its parent object by default. Now, look at the second example.
Example 2:
var stacy = {
name: 'stacy',
age: 33,
sayName: function() {
console.log(name);
console.log(this.name);
console.log(stacy.name);
}
}
stacy.sayName();
In the second example, the console.log(name) and console.log(this.name) will not be equal but console.log(this.name) and console.log(stacy.name) will be equal as per above example's logic.
And the story will be different if use arrow function in place of the function keyword. In arrow function, this keyword refers to the global object.