1

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
basum
  • 311
  • 3
  • 15
  • That's because you have global variables! `this` inside `inner` is still `window` which access the global variables. – Andrew Li Jun 15 '17 at 18:40
  • @AndrewLi okay, I get that, shouldn't inner access outer's bound a and b as it is a closure? – basum Jun 15 '17 at 18:41
  • No, because you're accessing `this` in the closure. It has nothing to do with the outside function. – Andrew Li Jun 15 '17 at 18:42
  • so you mean to say 'this' has nothing to do with the scope chain ? – basum Jun 15 '17 at 18:43
  • @AndrewLi , okay, so you mean to say while I defined the function this was assigned internally via the engine in the scope of the function? – basum Jun 15 '17 at 18:46
  • `this` is a value determined by execution context when the code is run. A new function invocation establishes an execution context, and in the case of function declarations `this` refers to the global context, referring to `window`. – Andrew Li Jun 15 '17 at 18:48

3 Answers3

3

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.

snovakovic
  • 184
  • 7
0

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})
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • so the interpreter internally checks first if a function call is a 'method' or a 'normal function call', in the former case, the this is the obj to which the method is attached, and in the latter, global object even if the function is a closure and not attached to global object [ Of course, in non-strict mode]. ? ? – basum Jun 15 '17 at 19:08
  • Yes, that's what it checks. Notice that it doesn't pass the global object though to `inner()`, it passes `undefined` - it's not attached to anything as you say. It's only sloppy mode functions that cast undefined this arguments to the global objects, just like arrow functions or bound functions choose to ignore the value. (Always try strict mode :D !) – Bergi Jun 15 '17 at 19:12
0

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

jramirez
  • 155
  • 9