0

I am reading this chapter in You don't know JS .

function baz() {
    // call-stack is: `baz`
    // so, our call-site is in the global scope
    console.log("baz");
    bar(); // <-- call-site for `bar`
}


function bar() {
    // call-stack is: `baz` -> `bar`
    // so, our call-site is in `baz`
    console.log("bar");
    foo(); // <-- call-site for `foo`
}

function foo() {
    // call-stack is: `baz` -> `bar` -> `foo`
    // so, our call-site is in `bar`
    console.log("foo");
    console.log(this);
}

baz(); // <-- call-site for `baz`

I was expecting the console.log(this) in function foo to print bar, since bar is the call site, but instead it seems to be window.

How is the this reference window instead of bar inside the function foo ?

user2434
  • 6,039
  • 16
  • 57
  • 84
  • 3
    __window__..... As `this` belongs to `owner` of the `method` being called!(If `.bind/.call/.apply` are not considered!) – Rayon Apr 21 '16 at 05:56
  • 3
    `this` isn't determined by the location of the call, just by the manner (how it was called). In all 3 cases, the functions are called simply as local functions (vs. as methods, etc.) – `fn()` – so `this` will be the default value, either the global object (`window` in browsers) or `undefined` (strict mode). This is discussed a few paragraphs after the snippet: [Default Binding](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/ch2.md#default-binding). – Jonathan Lonowski Apr 21 '16 at 05:58
  • this SO question will help you out :- http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work – F11 Apr 21 '16 at 06:03
  • @RayonDabre—there is no such thing as "owner", you might mean [*base* value](http://www.ecma-international.org/ecma-262/6.0/#sec-reference-specification-type). *foo* is called without a base value or its *this*, so when resolving its *this* value, *getBase* returns *undefined* and its *this* defaults to the global (window in a browser) object, or remains undefined in strict mode. – RobG Apr 21 '16 at 06:08
  • @JonathanLonowski—except in arrow functions of course. ;-) – RobG Apr 21 '16 at 06:10
  • @RobG, Agreed! :( _"A function's this is set by how it's called"_ does sound perfect :) – Rayon Apr 21 '16 at 06:14
  • 1
    @RayonDabre—well, that was true until *bind* (ES5) and arrow functions (ECMAScript 2015) were added to the language. ECMAScript 2017 may introduce more change (or not). ;-) – RobG Apr 21 '16 at 06:34

3 Answers3

4

As explained wonderfully by Kyle Simpson, the value of this depends on only 4 conditions depending on the call site:

var obj = {
  foo: function() {
    console.log(this);
  }
};

function foo() { console.log(this); }

1. Call using object(Implicit binding)

obj.foo();

In this case, foo is called using obj (always notice the object before the dot operator). Hence this refers to obj inside foo.

2. 'call' or 'apply' (Explicit binding)

foo.call(obj);

Here, this inside the function foo refers to obj since it has been binded explicitly.

3. Call using new (new keyword)

obj = new foo();

Inside foo, this now refers to the newly created object.

4. Global object (Default Binding)

foo();

Here, foo is called directly. Hence it defaults to window. (This is your case!)

As you can see, in your case, foo is called directly(case 4). Hence this refers to the window object. Just remember these 4 cases and you will be good!

Adarsh Konchady
  • 2,240
  • 4
  • 23
  • 42
0

'this' refers to the object that is calling the function, not the calling function. Are you running this code from a browser (i.e. from a web page)? If so, then 'this' is the window that the code is running in.

Peter Faller
  • 132
  • 1
  • 1
  • 5
  • 1
    *'this' refers to the object that is calling the function*. Only sometimes. A function's *this* is set by how it's called—with a base (i.e. as a method), without a base (as in the OP), with *call* or *apply*. The exceptions are the use of *bind* and lexically in an arrow function. – RobG Apr 21 '16 at 06:12
0

It is true that 'bar' is the call site but you have to see which of the 4 rules apply to the call-site. In this case, there is no new binding. Similarly we do not see either hard, explicit or implicit binding since the foo() is not executed as obj.foo(). Thus it is a clear case of default binding hence this points to the global object i.e. window

Rishi
  • 13
  • 3