Использование метода класса в глобальном контексте имеет `this` как неопределенное

У меня есть класс, в котором есть метод, использующий this. Я «обновил» экземпляр этого объекта и передал его метод переменной в глобальном контексте. Если я затем вызову свою глобальную функцию this, она не будет определена.

class Tests {
  logThis() {
     console.log(this);
  }
}

const globalFunc = new Test().logThis;

globalFunc(); // undefined

Теперь, если бы я только что использовал литерал объекта, тогда this является глобальным.

const someObject= {
    logThis2: function() {console.log(this)}
}

const globalFunc2 = someObject.logThis2;

globalFunc2(); // global object

В обоих случаях глобальный объект владеет кодом и должен предоставлять this в контексте выполнения globalFunc. Итак, почему разница в this для метода, сгенерированного классом?


person cham    schedule 06.07.2019    source источник
comment
Классы JavaScript всегда находятся в строгом режиме. Другие функции/контексты не находятся в строгом режиме, если нет оператора "use strict";. В строгом режиме this является undefined вместо глобального объекта, если он не указан.   -  person Paul    schedule 07.07.2019
comment
Спасибо @Paulpro. Так что насчет того, когда метод назначается. Является ли исходный this также привязанным к методу.   -  person cham    schedule 07.07.2019
comment
Нет, см. этот вопрос для получения информации о this в целом: stackoverflow.com/questions/3127429/ . функции не получают привязку к ним this. this определяется во время вызова функции, а не при определении функции. x.foo() вызывает функцию x.foo с помощью this === x. var y = { bar: x.foo }; y.bar( ); звонит x.foo с this === y. Принимая во внимание, что var z = x.foo; z( ); вызывает x.foo без this, что приведет к тому, что он будет undefined в строгом режиме, но по причинам наследия/bc он будет глобальным объектом в нестрогом режиме.   -  person Paul    schedule 07.07.2019
comment
Вы сохраняете ссылку на прототип, а не на прямое свойство объекта экземпляра. Придется сделать logThis прямым свойством в конструкторе класса, чтобы делать то, что вы хотите. constructor(){ this.logThis = this.logThis.bind(this) }   -  person charlietfl    schedule 07.07.2019
comment
Извините, @Paulpro, я до сих пор не понимаю, потому что в вашем примере z не находится в классе (т.е. не в строгом режиме) и находится в глобальном контексте. Таково положение вещей на момент звонка???   -  person cham    schedule 07.07.2019


Ответы (1)


Все classes, включая их методы, оцениваются в строгом режиме¹. Всякий раз, когда функция создается и ее тело находится в строгом режиме², внутреннее свойство [[mode]] функции устанавливается в строгий режим. Это позволит this оценить значение undefined, когда функция вызывается без контекста.


Соответствующие цитаты из спецификации:

1:

Все части ClassDeclaration или ClassExpression являются кодом строгого режима.

~ ES 262, 10.2.1 Код строгого режима


2:

  1. Если код функции для этого MethodDefinition является кодом строгого режима, пусть strict будет истинным. В противном случае пусть strict будет ложным.

[...]

  1. Пусть замыкание будет FunctionCreate(kind, UniqueFormalParameters, FunctionBody, scope, strict, прототип).

  2. Выполните MakeMethod(замыкание, объект).

~ ES 262, 14.3.7 Семантика времени выполнения: DefineMethod

person Jonas Wilms    schedule 06.07.2019