Установите это для требуемых стрелочных функций
Я пытаюсь установить 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
взят из окружающего кода?"Окружающий код - это область, в которой определяется функция, а не обязательно, где она вызывается.