4

So I've learned about hoisting, scope chains and execution context. However, I'm not able to grasp one particular thing. Are the variable object and the global object different objects? And, is the "Execution Context Object" the same as the global object?

Here's some code that I experimented with to get an answer.

let variable = 0;

function updateVar(value) {
  this.variable = value;  
}

updateVar(1);

console.log(variable);
// 0

/* 
If I remove the 'this' keyword in the updateVar() function, 
the console logs 1.
Why?   

Thank you for your help in advance! Julian

JDom93
  • 73
  • 6
  • because `this` is referring to the function and you have set a property of the function not the variable you declared. – Sonu Bamniya May 01 '20 at 09:51
  • 1
    this===window, it gets stored on the window object whereas variable does not, you'd need window.variable to access it – EugenSunic May 01 '20 at 09:55

1 Answers1

4

It sounds like you might be reading some outdated material. The term "variable object" hasn't been used in the specification since the 3rd edition in 1999. :-) The term from ES5 onward is environment record.

Are the [environment record] and the global object different objects?

Yes. But the global environment is a nested pair of environments: The outer one uses the global object as its binding object (which is roughly what "variable object" meant in ES3). Then there's an inner one for let, const, and class globals, which do not become properties of the global object. You can see that if you start with SetRealmGlobalObject in the spec, and follow where it does NewGlobalEnvironment, which creates a new object environment record using the global object for binding.

And, is the "Execution Context Object" the same as the global object?

An execution context has an environment record.

If I remove the 'this' keyword in the updateVar() function,
the console logs 1.
Why?

Because of the two nested global environments:

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|         environment record for global object bindings         |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   |  environment record for global declarative bindings  |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   |                                                      |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|                                                               |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

So when you do this at global scope:

let variable = 0;

it creates a binding in this inner global environment record:

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|         environment record for global object bindings         |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   |  environment record for global declarative bindings  |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   | variable: 0                                          |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|                                                               |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

When you do this:

function updateVar(value) {
  this.variable = value;  
}
updateVar(1);

during the call to updateVar, this refers to the global object. So this.variable = 1 creates a property on that object (which, because that object is the outermost binding object, is a global):

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|         environment record for global object bindings         |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| variable: 1                                                   |
|                                                               |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   |  environment record for global declarative bindings  |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   | variable: 0                                          |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|                                                               |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

When you do console.log(variable) at global scope, variable resolves to the declarative environment binding, and you get the value 0.

If you do this instead:

When you do this:

function updateVar(value) {
  variable = value;   // <=== No `this`
}
updateVar(1);

instead of creating a property on the global object, since variable resolves to the declarative environment binding, you're updating that binding:

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|         environment record for global object bindings         |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   |  environment record for global declarative bindings  |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|   | variable: 1                                          |    |
|   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+    |
|                                                               |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

With this in updateVar, you can see that it creates a property on the global object by using the variable on window (which is a proxy for the global object in browsers):

let variable = 0;
function updateVar(value) {
  this.variable = value;  
}
updateVar(1);

console.log(variable);
console.log(window.variable);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875