I'm trying to set
this
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});
[1]
[2]
f3
requireFromString
require(...)
The reason is because "fat arrow functions" always take their this
lexically, from the surrounding code. They cannot have their this
changed with call
, bind
, etc. Run this code as an example:
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');
You will only see face and such
.
So, as far as why that doesn't work in the case of f3
, it's because it's a self-contained module being required. Therefore, it's base-level arrow functions will only use the this
in the module, they cannot be bound with bind
, call
, etc etc as discussed.
In order to use call
on them, they must be regular functions, not arrow functions.
What does "lexical this
" mean? It basically works the same as a closure. Take this code for example:
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);
};
What will be the result? An error, info is not defined
. Why? Because the accessible variables (the scope) of a function only includes the variables that are available where the function is defined. Therefore, infoPrintingFunctionA
has access to info
because info
exists in the scope where infoPrintingFunctionA
is defined.
However, even though infoPrintingFunctionB
is being called in the same scope, it was not defined in the same scope. Therefore, it cannot access variables from the calling scope.
But this all has to do with the variables and closures; what about this
and arrow functions?
The this
of arrow functions works the same as the closure of other variables in functions. Basically, an arrow function is just saying to include this
in the closure that is created. And in the same way you couldn't expect the variables of fileA to be accessible to the functions of fileB, you can't expect the this
of the calling module (fileA) to be able to be referenced from the body of the called module (fileB).
TLDR: How do we define "surrounding code", in the expression "lexical this
is taken from the surrounding code?" The surrounding code is the scope where the function is defined, not necessarily where it is called.