I am having trouble to get my head around this one.
I am aware of scope chaining, callbacks in javascript, the value of this in the callbacks and hence the arrow functions.
In javascript, closures have access to variables of the enclosing function via the scope chain. So why the closure does not access the 'this' bound via Function.prototype.bind to the parent function of closure ? Is the variable 'this' not a part of the scope chain?
Ran the following code inside the chrome console :
a = 4;
b = 6;
function outer(){
function inner(){
console.log(`this.a is ${this.a} and this.b is ${this.b}`);
}
inner();
}
outer.bind({a:1,b:3})()
and the console threw back :
this.a is 4 and this.b is 6
This and closures are 2 different mechanisms in JS and should not be mixed.
this in outer function is completely separated from this in inner function.
In your example you are expecting for inner function to have lexical scope of this from outer function and that is just not how this is working. It is working like that if you are using arrow function because then this would be lexical and will point to this from outer function.
if you change your inner function to arrow function you can observe that behavior // this.a is 1 and this.b is 3
const inner = () => {
console.log(this.a is ${this.a} and this.b is ${this.b}
);
};
if you want to learn how this is behaving I highly recommend book from Kyle Simpson and it's free on github this & object prototypes
From the book.
To understand this binding, we have to understand the call-site: the location in code where a function is called (not where it's declared). We must inspect the call-site to answer the question: what's this this a reference to?
So like you can see position of inner function is not relevant to what this will bound to. rules that defines how this will be bound
after reading above link you should have more understanding on this in JS.
Is the variable 'this' not a part of the scope chain?
Yes, exactly. this
is not a variable, but a special keyword. It does get set at every function call, in your case inner()
. It doesn't matter what this
in the scope of outer
was.
There's an exception though, where functions can opt out of this behaviour: arrow functions. They indeed look up this
lexically, and ignore the value from the call:
function outer(){
const inner = () => {
console.log(`this.a is ${this.a} and this.b is ${this.b}`);
}
inner();
}
outer.call({a:1,b:3})
As mentioned in the comments, this is a contextual reference and it can change based on how you are invoking the function (or defining it, if we considere arrow functions). Look at a modified version of your code that shows this contextual behavior:
var a = 4;
var b = 6;
function outer(){
document.write(`<p>[outer] this.a is ${this.a} and this.b is ${this.b}</p>`);
function inner(msg){
document.write(`<p>[${msg}] this.a is ${this.a} and this.b is ${this.b}</p>`);
}
inner('inner');
this.inner = inner;
this.inner('this.inner');
}
outer.bind({a:1,b:3})();
It will output:
[outer] this.a is 1 and this.b is 3
[inner] this.a is 4 and this.b is 6
[this.inner] this.a is 1 and this.b is 3
Working demo here