Установите это для требуемых стрелочных функций

Я пытаюсь установить this в разных сценариях.

Следующий код выполняется в node.js v6.8.1 напечатает то, что прокомментировано в конце каждой строки:

function requireFromString(src) {
  var Module = module.constructor;
  var m = new Module();
  m._compile(src, __filename);
  return m.exports;
}

(function(){
  var f1 = (() => {console.log(this.a === 1)});
  var f2 = function(){ console.log(this.a === 1) };
  var f3 = requireFromString('module.exports = (() => {console.log(this.a === 1)});');
  var f4 = requireFromString('module.exports = function(){ console.log(this.a === 1) };');

  console.log('Body:');
  console.log(this.a === 1);                          // true
  (()=>console.log(this.a === 1))();                  // true
  (()=>console.log(this.a === 1)).call(this);         // true
  (function(){console.log(this.a === 1)})();          // false
  (function(){console.log(this.a === 1)}).call(this); // true


  console.log('\nFunctions:');
  f1();                                               // true
  f1.call(this);                                      // true
  f2();                                               // false
  f2.call(this);                                      // true
  f3();                                               // false [1]
  f3.call(this);                                      // false [2]
  f4();                                               // false 
  f4.call(this);                                      // true

}).apply({a:1});

С помощью документации для функций this и arrow я могу объяснить все случаи, кроме тех, которые помечены [1] а также [2],

Может кто-нибудь пролить свет на наблюдаемое поведение? И, возможно, дать подсказку, как я могу позвонить f3 так что функция печатает true.


Заметки

  • requireFromString -функция адаптирована из модуля Load node.js из строки в памяти и является всего лишь хаком, чтобы уменьшить этот вопрос о переполнении стека. На практике это заменяется обычным require(...)

1 ответ

Решение

Причина в том, что "жирные стрелки" всегда берут свои this Лексически, из окружающего кода. Они не могут иметь свои this изменилось с call, bindи т. д. Запустите этот код в качестве примера:

var object = {
  stuff: 'face',

  append: function() {
    return (suffix) => {
      console.log(this.stuff + ' '+suffix);
    }
  }
}
var object2 = {
  stuff: 'foot'
};

object.append()(' and such');
object.append().call(object2, ' and such');

Вы увидите только face and such,

Итак, насколько это не работает в случае f3это потому, что требуется автономный модуль. Поэтому функции стрелок базового уровня будут использовать только this в модуле они не могут быть связаны с bind, callи т. д. и т. д., как обсуждалось.Для того, чтобы использовать callна них они должны быть обычными функциями, а не функциями стрелок.


Что значит "лексический"this "значит?Это в основном работает так же, как замыкание. Возьмем этот код, например:

fileA.js:

(function () {
    var info = 'im here!';

    var infoPrintingFunctionA = function() {
        console.log(info);
    };

    var infoPrintingFunctionB = require('./fileB');

    infoPrintingFunctionA();
    infoPrintingFunctionB();
})();

fileB.js:

module.exports = function() {
    console.log(info);
};

Каким будет результат? Ошибка,info is not defined, Зачем? Поскольку доступные переменные (область действия) функции включают в себя только те переменные, которые доступны там, где определена функция. Следовательно, infoPrintingFunctionA имеет доступ к info так какinfoсуществует в области, гдеinfoPrintingFunctionAопределено.

Тем не менее, даже еслиinfoPrintingFunctionB вызывается в той же области, она не была определена в той же области. Следовательно, он не может получить доступ к переменным из вызывающей области.

Но все это связано с переменными и замыканиями; как насчет this а стрелки работают?

thisСтрелка функций работает так же, как закрытие других переменных в функциях. В основном, функция стрелки просто говорит, чтобы включить this в замыкании, которое создано. И точно так же вы не могли ожидать, что переменные файла A будут доступны для функций файла B, вы не можете ожидать this вызывающего модуля (fileA), на который можно ссылаться из тела вызываемого модуля (fileB).

TLDR: как мы определяем "окружающий код" в выражении "лексический" this взят из окружающего кода?"Окружающий код - это область, в которой определяется функция, а не обязательно, где она вызывается.

Другие вопросы по тегам