2

My understanding of JavaScript is that on script execution a global execution context is created - what I understand to be a series of key:value pairs in reserved memory space - much like a regular JavaScript object.

On function execution, a new execution context is created with access to the 'parent' execution context. This seems (to me) at least to be the equivalent of re-initializing the JavaScript execution environment. Except that non of the key:value pairs initially set up in the global object need to be added to the new execution context since the child execution context has access to the parent's key:values pairs.

So for example:

function Y() {
   this.prop = 4;
};

Y.prototype.doY = function() {
  console.log(this.prop);
};

function X(){
  this.prop = 5;
  this.y = Object.create(Y.prototype);
  Y.call(this.y);
};

// I can instantiate the object like so:
var x = new X();

// Which is equivalent to the following:
var x = Object.create(X.prototype);
X.call(x);

// Then I can add a function to the object that the X constructor points to via the X.prototype reference:
X.prototype.doX = function() {
  console.log(this.prop)
};

// And then i can execute doX() in the context of the x object
x.doX(); // 5
x.y.doY(); // 4

On execution, doX function creates an execution context referenced from within the x object. The x object in turn is referenced within the global object.

Likewise, on execution the doY function creates an execution context that is referenced from within the x.y object.

It seems to me that an execution context as created by function execution is basically equivalent to a JavaScript object from a logical point of view:

  • Both allow for variable declaration NOT visible to parent objects/execution contexts
  • Both contain some kind of internal reference to parent object/execution context

It seems that both objects and execution context are just a list of key:values, the whole list being referenced by a single (ONLY a single) parent object (i.e. the y object exists as a reference within the x execution context) - or the global object as the root parent object (the x object exists as a reference within the global execution context).

So the question is: Is JavaScript execution context the same as a JavaScript object? If not, what is the difference?

This question: Are Execution Context and Variable Object actually same thing in JavaScript? mentions that in terms of implementation, that an execution context and an object are NOT the same thing.

Would it be correct to say that execution context inherits from Object? Or is implementation of objects/execution contexts completely non-related... One difference that I can see is that on creation, an execution context is 'processed' from top to bottom (lexically speaking) allowing an author to specify imperative commands - i.e. instruct the computer to do things. But in terms of architecture, this difference seems like an extension of the idea of an object rather than something completely different.

It seems to me that a 'running JavaScript environment' if such a thing exists, is basically a tree. The root node is the global execution context, and creating object adds nodes to the root node, or (as in the case of y above), adds nodes to the child nodes. Child nodes then reference parent nodes via a property to allow for scoping to parent execution context.

Then in terms of closures, which involve creation (and execution) of an execution context, on return the resultant object seems EXACTLY like a regular object since the 'execution context' as referenced by the closure will never again be executed (i.e. the same function, re-executed would create a new execution context and closure).

So from an "applied" point of view, is there ever a time that this -> i.e. a self reference to the current execution context, is NOT the same as the object from which a function call is made (aside from when using call, apply, or bind)? i.e. in the case of x.y.doY(), the function doY is called from the x.y object.

Zach Smith
  • 8,458
  • 13
  • 59
  • 133
  • Unrelated, but why would you use `this.y = Object.create(Y.prototype); Y.call(this.y);` rather than `this.y = new Y();`? It's just more work and confusing to read... – T.J. Crowder Jan 24 '18 at 08:41
  • because it's explicit - i.e. that an object is created, and that `Y` is called in the context of the newly created object. In my code i use `new Y()` – Zach Smith Jan 24 '18 at 08:55
  • just as a matter of interest @T.J.Crowder. Is there another way I could create an object and then repoint the prototype? i.e. is that the equivalent of `this.y = {}; this.y.__proto__ = Y.prototype`? – Zach Smith Jan 24 '18 at 08:56
  • 1
    I'm not entirely sure I understand the question. `this.y = new Y();` and `this.y = Object.create(Y.prototype); Y.call(this.y);` do the same thing (because `Y` is defined via `function`; if it were defined via `class`, the latter wouldn't work). But yes, you can change the prototype of an object. If the object has `__proto__`, you can do it the way you did above, but by far the better way is to use `Object.setPrototypeOf` (not least because not all objects have `__proto__`). But changing the prototype of an object after creation is best avoided. – T.J. Crowder Jan 24 '18 at 09:02
  • In your view, where would you store the context of an anonymous function? – RaphaMex Jan 24 '18 at 09:23
  • @RaphaMex. conceptually i would not store a reference to it from the current execution context. So i see it as 'orphaned'. The parent couldn't reference it, but the child holds a reference to the parent. no idea if this is correct – Zach Smith Jan 24 '18 at 09:37

3 Answers3

4

Execution contexts are conceptually objects, yes, as are several other things in the specification. That doesn't make them the "same" as JavaScript objects. They're a specification device and may not literally exist at runtime at all; code cannot directly reference them. For the full picture, read Executable Code and Execution Contexts in the spec.

Is JavaScript execution context the same as a JavaScript object?

No. A JavaScript object can be directly referenced by code, has a prototype, and has specific behaviors described for it which are not described for execution contexts, etc.

Would it be correct to say that execution context inherits from Object?

No, nothing in the spec suggests that to be the case.

It seems to me that a 'running JavaScript environment' if such a thing exists, is basically a tree.

Sort of, fairly indirectly. The spec doesn't describe any link from an execution context to its parent or child contexts. Instead, the lexical environment objects which are part of the context's state (specifically the LexicalEnvironment and VariableEnvironment state components) have a link to their parent lexical environment for the purposes of binding resolution. (The parent lexenv doesn't have a link to its children in the spec.) But they, too, are purely a specification device which may not literally exist at runtime and cannot be directly referenced by code.

So it's absolutely correct to think of them as objects, that's how the spec describes them, but they aren't JavaScript objects in the way that term is normally understood — something code can directly reference and act upon.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you. I think I understand that the tree I was referring to is built via lexical parsing. And that the execution context is created and nodes from the lexical tree are included in that execution context? – Zach Smith Jan 24 '18 at 09:40
2

No, they are not the same thing. Not at all.

First, you seem to be confusing execution contexts with environment records. The former are basically call stack frames, the latter ones store variable values and form a tree as you described. Let's talk about environment records.

Environment records feature a key-value mapping and a link to their parent environment. In that regard, they are similar to a JS object with its properties and prototype link indeed. In fact, in a with statement or the global scope a so called object environment record is backed by an actual JS object.
However, they are still very different. Most environment records are declarative, that means their shape is determined before they are used. They are like an object that is not extensible. Also they cannot have getter/setter properties. And they differ in many more minor details.

But most importantly, environment records are just specification type values. They "are specification artefacts that do not necessarily correspond to any specific entity within an ECMAScript implementation. Specification type values may be used to describe intermediate results of ECMAScript expression evaluation but such values cannot be stored as properties of objects or values of ECMAScript language variables." So no, they do not inherit from Object at all.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

Your question seems to ask: what can execution contexts record do that cannot be recorded in javascript objects?

You've got well documented answers already. So my contribution will be practical examples.

How would you manage the following 2 examples from a key/value perspective:

// Execution context of anonymous functions
(function (x) {
    var y = x+1;
    console.log(y);
}) (1);

// Life cycle of objects versus reference
var x = {a:1};
var y = x;
x = {b:1};
console.log(y);

If you start inventing keys that are not in the code, you should realize that this approach is limited. And so, not working if you push beyond the limits.

RaphaMex
  • 2,781
  • 1
  • 14
  • 30
  • I didin't realize that in the second example, y id declared as a reference to the object referenced by x and not the x reference itself. But I don't know what you mean by inventing keys that are not in the code? – Zach Smith Jan 24 '18 at 09:50
  • You base your reasoning on context being key/value records, keys being function/variable names. Instead, you should see it as key/reference records. But then, what key would record the reference/value? That's where you would need to *invent* keys, e.g. making arrays of references and re-implementing heap and stack in your object. – RaphaMex Jan 24 '18 at 10:03
  • I would say that holding a reference to the execution context created on invocation of an anonymous function is not necessary at all, instead that execution context would hold a reference to the parent execution context somehow, made available to the user as the `this` variable (i.e. being lexically scoped to the global context). The var `y` would only exist within the anonymous execution context. But I see what you mean by variable names not being keys referencing objects within the execution context themselves, but rather an abstraction of such references. Is that correct? – Zach Smith Jan 27 '18 at 07:52