Lexical Scope in JavaScript
Asked Answered
D

4

7

I am slightly confused as to how exactly scope works in JavaScript, mainly lexical scope. I understand that variables in global scope are accessible anywhere, and the only way to create a new scope in JavaScript is through the creation of functions (or with let in ES6). However, I do not really understand what lexical scope is/means. I have looked all over the internet and could not find a clear explanation.

I feel like I am kind of starting to understand it, but just let me confirm with you JavaScript wizards out there to make sure that I am correct.

So, from my understanding, lexical scope means statically scoped, so for example, a function's scope is not created by where it is called but by where the function itself is created. The following code below demonstrates this concept:

var x = "global";

function foo() {
   console.log(x);
}

function bar() {
   var x = "bar";
   foo();
}

function baz() {
   var x = "baz";
   foo();
}


bar();
baz();

What is printed to the console is "global" twice. This is because when the function foo is invoked, the interpreter first checks foo's scope to see if it has a variable "x" then checks the global scope, not bar or baz scope. The variable "x" is grabbed, not from where the function foo is called, but from where it is created, hence lexically scoped. Am I correct, and is this making sense?

Another example of lexical scope would be closures, right? So for example, the inner function has access to the outer function's variables, no matter where the inner function is called because of lexical scope, correct?

Finally, my last example would be arrow functions. They allow for the lexical scoping of "this", right? So, for example,

   var obj = {
       name: "Rob",
       print() {
       setTimeout(() => {
         console.log(this.name)
       }, 1000);
     }
   };

Rather than "this" being bound to the global object if it were a standard inline function, "this" is bound to obj because of the lexical scoping of "this" with arrow functions.

Is everything I have said correct? Also, can someone just give me a clear-cut definition of lexical scope? Are there any other examples of lexical scope in JavaScript that I should know about?

Thanks.

Direction answered 17/1, 2018 at 6:56 Comment(3)
foo, bar, and baz in your first example are closures. Your thoughts are generally on the right track.Pooley
You can read more about it here. https://mcmap.net/q/20882/-what-is-lexical-scopeVada
Please elaborate as to why they are closures. A closure is an inner function that has access to the outer function's variables, even after the outer function has returned. That is not the case in the foo, bar, and baz example.Direction
N
2

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:

this.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:

this.values.filter( function ( x ) { return x < this.max }.bind( this ) );

or:

var self = this;
this.values.filter( function ( x ) { return x < self.max } );
Nil answered 17/1, 2018 at 7:32 Comment(3)
Awesome explanation of an arrow function's "this." Thank you for clearing that up! So you said that my understanding of regular functions is correct, but is my understanding of closures correct?Direction
@E.Sawyers Yes, I think your understanding of how lexical scope works for closures is correct, but maybe your understanding of what makes a function a clouse. A closure is any function that uses a non-local variable. By that definition foo is a closure since it references x which is not a local variable in that function, but bar and baz are not closures since they only reference they're own local x variables.Nil
Thank you so much for your help!Direction
C
5

To understand the lexical scope you need to have a basic understanding of the scope. In javascript, we have classified scope in three types

  1. Function scope
  2. Block Scope
  3. 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.

   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" `

var 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

Cushman answered 30/5, 2019 at 8:8 Comment(0)
N
2

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:

this.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:

this.values.filter( function ( x ) { return x < this.max }.bind( this ) );

or:

var self = this;
this.values.filter( function ( x ) { return x < self.max } );
Nil answered 17/1, 2018 at 7:32 Comment(3)
Awesome explanation of an arrow function's "this." Thank you for clearing that up! So you said that my understanding of regular functions is correct, but is my understanding of closures correct?Direction
@E.Sawyers Yes, I think your understanding of how lexical scope works for closures is correct, but maybe your understanding of what makes a function a clouse. A closure is any function that uses a non-local variable. By that definition foo is a closure since it references x which is not a local variable in that function, but bar and baz are not closures since they only reference they're own local x variables.Nil
Thank you so much for your help!Direction
D
1

When you look at some source code of a program, you are looking at its lexical structure. When the program actually runs, execution can jump around and evaluation of things can change.This is the part that all start making sense.

You may want to look at it as functional lexical scope and block lexical scope. For the rest, you already seem grasped the idea of it.

Dannielledannon answered 17/1, 2018 at 7:24 Comment(0)
A
-1

"global" is printed twice because "foo" is a closure that has added "x" of the global scope to its memory, thats the way I learned, closure are functions that remember

Aragon answered 17/1, 2018 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.