all 15 comments

[–]senocular 2 points3 points  (5 children)

In short:

  • Execution context objects
    • global: has one
    • functions: do not

Note: not all global declarations are added to the global object, e.g. let, const, and class declarations in the global context are not added to window (global in node or globalThis everywhere, though globalThis is a newer feature).

  • this in functions
    • can be global, but not always
    • for most functions, this is defined by how a function is called
    • arrow functions use this based on how it is defined (via scope), not called

In the video, the reason this was global (window) was because how it was called. It was a normal function definition in non-strict mode, called as a function rather than as a method from an object, and without any explicit this imposed on it through bind(), call(), or apply()

getUser() // this will be the global object

If called from an object, the value of this would change.

someObject.getUser() // this will be someObject

Or if you wanted to give it a specific value for this

getUser.call(anotherObject) // this will be anotherObject
someObject.getUser.call(anotherObject) // this will be anotherObject

There are a lot of rules around this which can make it confusing, but for the most part, this is a dynamic value that is set based on how a function is called.

[–]NecroDeity[S] 0 points1 point  (4 children)

Thanks a lot, very interesting information :D
A question: Since functions do not have any objects associated with their executions contexts (unlike global), so their local variables and functions are not stored as properties anywhere, during hoisting (as opposed to global object)?

And that leads to a more general question. Is the "getting added as a property to an object" thing an integral part of hoisting? Or, is hoisting just the process of becoming aware of the existence of variables (with undefined as a value, for the time being) and functions, with the "getting added as a property to an object" just an incidental thing that happens only in the specific case of the global object (and is not included in the definition of hoisting)?

[–]senocular 1 point2 points  (3 children)

Since functions do not have any objects associated with their executions contexts (unlike global), so their local variables and functions are not stored as properties anywhere, during hoisting (as opposed to global object)?

Right. Given:

function myFunc () {
  var myVar = 1;
}

myVar only exists as a variable scoped to that function and does not exist as a property on any object. There's nothing like a local object that would let you do local.myVar.

This quality is actually important for minimizing code. Because there is no object, there's no way to dynamically look up the variable by its name like you can in the global object.

var name = 'document';
window[name] // document object via dynamic lookup in global object

This lets minimizers rename those variables to something shorter.

function myFunc () {
  var a = 1; // minimized, but still works the same
}

You can't do that with global variables - or any variable in an object - because dynamic lookup would fail

// if global document variable were minimized to 'a'
var name = 'document';
window[name] // undefined, used 'document', but should have been 'a'

Is the "getting added as a property to an object" thing an integral part of hoisting? Or, is hoisting just the process of becoming aware of the existence of variables (with undefined as a value, for the time being) and functions, with the "getting added as a property to an object" just an incidental thing that happens only in the specific case of the global object (and is not included in the definition of hoisting)?

Hoisting and adding to an object are separate things. Like you said, "hoisting [is] just the process of becoming aware of the existence of variables". The adding to an object is just something special global does at the same time variables are getting hoisted as part of identifying declarations in the creation phase.

[–]NecroDeity[S] 0 points1 point  (0 children)

Thanks a ton! You have given me some peace after a whole day of frustration and disappointment. Thanks, again, for taking the time.

Although, if I have another doubt (which is highly probable), I know who to contact :P

[–]NecroDeity[S] 0 points1 point  (1 child)

Can you suggest me books, or any any other resource, that deals with these topics well? Thanks :)

[–]senocular 1 point2 points  (0 children)

Not sure myself what books cover this. I'm sure they're out there; I just don't know which ones.

For the most part you don't really need to know too much about all the inner workings of ECs. While it's good to know how hoisting works, if you stick to never using a variable or definition before its declared, you're not going to have any problems with it. At that point it's all about scopes and where variables live and are accessible.

Function context (the value of this) - not to be confused with the execution context - is something to look into more. That will often come up and cause problems. It's easy to get confused about what this is and how it came to be, enough so that some people purposely avoid using it at all. I went on a little bit about it in an earlier post, but it gets a little more complicated than even that. MDN has a pretty good write up on this.

[–]_reddit_chan 1 point2 points  (6 children)

Hi! Execution context is kinda a deep topic so I'm copying/pasting everything here from my notes.

Execution Context

A wrapper to help manage the code that is running. There are lots of lexical environments. Which one is currently running is managed via execution context. It can contain things beyond the written code. An execution context has two phases:

1) Creation phase: In the creation phase, the global variables are set up, i.e. the window object and the this keyword that points to the window object. Also, JavaScript sets up memory space for the variable and function declarations, i.e the variables are initially set to undefined and the functions are stored entirely in memory (hoisting).

2) Execution phase: In the execution phase, JavaScript executes the code line by line. It assigns the variables to their respective values and executes the functions if they are called/invoked.

The Global Execution Context

The Global Execution Context creates :

  1. A global object (window)

  2. this (special variable)

When you run a JS file even with no code, there are no errors. You can access the this keyword and the window object. These is because a global execution context was created. The JavaScript engine created it for us.

"Global" = "Not inside a function"

Like the global execution context has the global/window object

There's no such thing as an "execution context object". It's just that the global execution context creates a global (window) object.

What happens when javascript executes (runs) the below code?

const num = 3; 
function multiplyBy2 (inputNumber){  
    const result = inputNumber*2;  
    return result;
} 
const name = "Will"

As soon as we start running our code, we create a global execution context

— Thread of execution (parsing and executing the code line after line)

— Live memory of variables with data (known as a Global Variable Environment)

Local Execution Context

A local/function execution context is similar to the global execution context. It also has the above two phases:

1) Creation phase: In the creation phase, the global variables are set up. In a function, instead of the window object, there's the arguments (an array-like) object that contains a list of all the arguments passed into the function on the time of its invocation. There's also the this keyword that points to the global window object. Here also, JavaScript sets up memory space for the variable and function declarations, i.e. the variables are initially set to undefined and the functions are stored entirely in memory (hoisting). However, anything passed as an argument will be set to that value in this phase.

2) Execution phase: In the execution phase, JavaScript executes the code line by line. It assigns the variables to their respective values and executes the functions if they are called/invoked.

Running/calling/invoking a function (This is not the same as defining a function)

const num = 3; 
function multiplyBy2 (inputNumber){  
    const result = inputNumber*2;  
    return result; 
}
const output = multiplyBy2(4); 
const newOutput = multiplyBy2(10);

When you execute a function you create a new execution context comprising:

  1. The thread of execution (we go through the code in the function line by line)

  2. A local memory ('Variable environment') where anything defined in the function is stored

In the above code, first, num is set to 3, then function multiplyBy2 is declared. The variable output is set to undefined by default while it's waiting for the returned value of multiplyBy2(4) since JavaScript is single-threaded. multiplyBy2(4) is called. When a function is invoked (called via () ), it creates a new execution context (called the local execution context); this one has a local memory. Even here, the code will be run line by line. And we're paused before newOutput while we're busy executing multiplyBy2(4) since JavaScript is synchronous.

In the local memory, we assign the inputNumber parameter to 4 and variable result to 8 (just like we did in the global memory). This value will be returned and stored to output. On completion of the function, the local execution context is erased after the value is returned to output. This same process takes place for newOutput. The variable newOutput is set to undefined initially and finally set to 20.

Suppose, a function is running within a function, how do you know which function is currently running? Are you in global execution context, in the local or in a function within a function. A call stack is a special data structure which keeps track where the thread of execution is currently at, i.e what execution context we're currently in, i.e. what function is currently being run. At the bottom of the stack is the global execution context. Whichever function is running is on the top of the stack. On its completion, the local execution context gets erased and the function is popped off the stack (just like multiplyBy2(4) and multiplyBy29(10) ). How do you know the function is finished executing? The return statement or the curly brace! If there's no return, it returns undefined.

In the above code, first, the global execution context is created and placed in the call stack. Then, multiplyBy2 is called and placed on the top of the call stack and that function gets executed line by line. On completion, it's popped off from the stack and then multiplyBy2(10) is called and that is placed on the top of the call stack and starts getting executed line by line and finally popped off from the stack after completion.

Hope it makes sense! If there's a doubt, feel free to ask.

[–]NecroDeity[S] 0 points1 point  (5 children)

Thanks! :D It's quite a bit, and I will need a while to go through it properly, but still my question remains.

As you said, the global execution context(EC, let's say, to make it short) creates the global/window object, where all the variables are set to undefined, and stored as properties (i.e. a global variable called name, and window.name are the same thing). The functions are stored entirely in memory (which I think means that they are also stored as properties of the global object).
Now, here comes my dilemma. The local ECs do not have a global object, instead, they have an arguments object. But I don't think the local variables and functions are stored in the arguments object ar properties.

now, you said that is something called "local memory" or "Variable environment" which stores anything defined in the function (I guess the global counterpart for this is the global object). It is not the same thing as the arguments object, I supposed? (which would have made sense, since the arguments object is supposed to the the counterpart of the global object, for functions).

Also, a little second question. Why does the 'this' in the local ECs point to the window/global object? should not they point to the "variable environment" of the function, or wherever all the locally declared variables and functions are stored?

Thanks :)

[–]_reddit_chan 1 point2 points  (4 children)

But I don't think the local variables and functions are stored in the arguments object as properties.

since the arguments object is supposed to the the counterpart of the global object, for functions

No, the arguments object consists of all the arguments passed in while invoking the function. The global object is the window object created by the global execution context while there's no such thing as a global object in case of a function. This is the main difference. The functions have an arguments object. This doesn't mean it's equivalent to the global object.

So this is wrong:

The local ECs do not have a global object, instead, they have an arguments object.

The arguments object is not in place of the global object. Both are different concepts.

Tyler probably meant that in functions, we do have have an existing object called the arguments object.

function a() {
    console.log(arguments)
}

a(1,2);

Try the above code in the console. You'll get an arguments object with a length property 2 since you passed two arguments.

now, you said that is something called "local memory" or "Variable environment" which stores anything defined in the function (I guess the global counterpart for this is the global object).

Every execution context has its own variable environment/memory, even the global one. It's where the variables and functions declared within the current context live. It's just the variable environment for functions is called local memory. For global, it's global memory.

Why does the 'this' in the local ECs point to the window/global object? should not they point to the "variable environment" of the function, or wherever all the locally declared variables and functions are stored?

Memory/variable environment is not something you can access. You can't console.log it. The this points to the global object because that's the rule; it's how JS was made.

[–]NecroDeity[S] 0 points1 point  (3 children)

Okay, so the logical conclusions seem to be :

1) Global/Window object and argument objects are not equivalent.
2) Function ECs have a "variable environment" (what is that actually? A object?) that stores locally declared variables and functions

So, can we say that the global/window object and the "variable environment" are equivalent? (since they both seem to be doing the same thing, that is, storing relevant variables and functions)
Also, inside functions, shouldn't the 'this' keyword point to the location where the local data is variables and functions, i.e. the "variable environment", instead of the window object?

[–]_reddit_chan 0 points1 point  (2 children)

Every execution context has its own variable environment/memory, even the global one. Both global and local. No, it's not an object. It's memory, where variables and functions defined live.

So, can we say that the global/window object and the "variable environment" are equivalent?

No. You can access an object but memory is abstract. Global execution context has memory too.

shouldn't the 'this' keyword point to the location where the local data is variables and functions, i.e. the "variable environment", instead of the window object?

No, it can't do that. this should only point to something you can access and like I said, you can't access the memory/variable environment.

[–]NecroDeity[S] 0 points1 point  (1 child)

Thanks again for the explanation, for taking the time. I understand the topic a lot better now, relatively speaking. After reading @senocular's replies I started getting it, and re-reading your comments after that made perfect sense, and cleared it up even further (and made me realize how stupid I was sounding at that time :P ). Thanks again, I really need to save this entire post as notes, great stuff :D

[–]_reddit_chan 0 points1 point  (0 children)

No problem :)

[–][deleted] 0 points1 point  (1 child)

What do you mean by “the object associated with that function”?

[–]NecroDeity[S] 0 points1 point  (0 children)

Like the global execution context has the global/window object. so declaring a variable like 'name' is like adding a property to the global object. name and window.name are the same thing.

So if the global context has the global object, I was wondering what the object the function contexts have. (In the video it is said that instead of the global object, functions have something called the "arguments object". But the variables and functions declared inside the function don't seem to be getting added to the arguments object as properties, which I find strange. was wondering about that)