Home > other >  How is the 'this' keyword parsed by the JS engine during the compilation phase?
How is the 'this' keyword parsed by the JS engine during the compilation phase?

Time:11-27

function foo(bar) {
  this.name = bar;
}

During the compilation phase, when the JavaScript Engine is compiling the function foo, I understand that it registers bar in the scope of foo, but how is this.name parsed ? Given that the execution context that this points to is determined by the call-site of the function, does this mean that this is not parsed at all until run-time ? I know that value assignment occurs during run-time and we're assigning a value (name) on an object(this), so I'm assuming the line this.name = bar is not parsed at all from the perspective of scope resolution. Is this correct ?

CodePudding user response:

"Parsing", "scope resolution", "compilation" (optimization, jit, or whatever, if at all), "run-time", can all be conceptualized as separate phases (which might be intertwined in the actual implementation).

In an actual implementation, the this-keyword-token is most likely parsed just like any other reserved keyword token during the parsing phase, nothing special about that.

The scope of the this-keyword can be determined statically, just like the scope of variables like bar. Consider this more interesting example to understand what it means:

var f = function(x) {
  var g = (y) => {
    this.name  = x * y;
  }
  return g
}

In this example, we would know statically during the scope-analysis phase that:

  • this is the receiver of f (which will be bound dynamically at the invocation site of f, i.e. we can know statically that it belongs to f, but we don't know until runtime what the receiver might be)
  • x is a parameter of f
  • y is a parameter of g
  • name is just a statically known constant stringy-valued property name; It has no "scope" at all, you can think of it as a hard-coded constant this['name'] = ....

The value that is used during the evaluation of this is bound at the call site at runtime, it's either the receiver if the function is called as a method, or a suitable global object / module if f is called as stand-alone function without a receiver.

Note that the specification does not force the interpreter to analyze anything statically: this is an implementation detail that is left to the one who implements the interpreter. A really sophisticated interpreter might decide to perform some escape analysis, and when it finds that, for example, some nested helper functions don't escape the scope of the enclosing function, it might try to compute the receivers ahead of time, or to inline the entire helper function at the call site.

CodePudding user response:

It's parsed at parse time, which you might also call compile time, but the distinction is tricky in modern optimised JITs. Either way, scope resolution is static, and the scopes involved in the expression this.name are resolved at the same time as the scope of bar.

The scope of the this keyword is the function (just like for the bar variable in your example), you can think of it as constant variable in the function scope, initialised from an invisible zeroth argument.

.name is not resolved at all since it's not a variable, it's a property name. The location in the target object will depend on the particular object; the property is looked up right when the assignment happens, when the function is called.

CodePudding user response:

You've mentioned three different stages of code processing: parsing, compilation, and runtime.

During the compilation phase

Indeed, some interpreters may introduce compilation for optimization reasons, but this kind of compilation is not the same thing as compilation in Java or other compiled languages; e.g., you don't get to see compilation errors (an example of such error would be number is not assignable to a string). For this reason, JavaScript is thought of as an interpreted language, not compiled one.

does this mean that this is not parsed at all until run-time ?

It is parsed, but not compiled. The expression this.name = bar is parsed as

<left-hand-operand> <binary-operation> <right-hand-operand>

… and evaluated at runtime as (roughly) "take the value of bar and put it to this.name". If this cannot be done for some reason (e.g., if this is nullish), there will be a runtime error.

  • Related