3

class Obj {
  static log(){
    console.log(this)
  }
}

var test = Obj.log

Obj.log() // class Obj
test() // undefined

This is the code I run without 'use strict'. The result I don't understand. Why does the function test log undefined instead of the global object?

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
李晓爽
  • 81
  • 7

1 Answers1

6

It's because class code is always strict code. From the spec

NOTE     A class definition is always strict code.

Since class code is always strict, the method log is a strict function (so amongst other things, its internal [[ThisMode]] slot is set to strict), and when you call a strict function without setting this, this is set to undefined for the call.

The chain of operations in the spec that sets this up is that a direct call expression is evaluated by eventually calling the spec's abstract EvaluateDirectCall operation with thisValue set to undefined. That in turn calls Call passing along the thisValue, which calls [[Call]] on the function passing thisValue as thisArgument, which calls OrdinaryCallBindThis, which checks the function's [[ThisMode]] and, if it's strict, sets the thisValue to thisArgument directly without further logic (whereas if it weren't strict, it would replace null and undefined with the global object and do ToObject on any other values).

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • OrdinaryCallBindThis ( F, calleeContext, thisArgument ). test.call(obj, list). In this situation, F means test, calleeContext means obj, thisArgument means list. Is this right? – 李晓爽 Mar 25 '17 at 08:41
  • @李晓爽: No. *F* is `test` and *thisArgument* is `obj`. The *calleeContext* is the [execution context](http://www.ecma-international.org/ecma-262/7.0/index.html#sec-execution-contexts) created by [[Call]]'s call to [PrepareForOrdinaryCall](http://www.ecma-international.org/ecma-262/7.0/index.html#sec-prepareforordinarycall). (My link to [[Call]] above was wrong, btw, I've fixed it.) – T.J. Crowder Mar 25 '17 at 08:49