-1
var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  console.log(this); // <nav> element
  setTimeout(function () {
    console.log(this); // [object Window]
  }, 1000);
};

In the example code above, why is this in line 3 the element when the variable nav is declared outside of the scope of toggleNav? Thanks

kurokuro
  • 1
  • 1
  • This is a funny thing in JS. Check out this post https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work – Hans Krohn Aug 25 '21 at 01:19
  • The callback function is called without context. From the dupe target: use arrow functions as your callback, or use `function(){`…`}.bind(this)` – Sebastian Simon Aug 25 '21 at 01:32
  • @SebastianSimon—all functions are called within an execution context, the difference is how the function's *this* is set depends on how it's called (and lexically with arrow functions). ;-) – RobG Aug 25 '21 at 01:46
  • @RobG I know… The word “context” is overused. It should probably be “implicitly `this`-binding base reference” or so. – Sebastian Simon Aug 25 '21 at 01:49
  • If you want to fix this you can try this: `var toggleNav = () => { console.log(this); // – DJ Burb Aug 25 '21 at 01:51
  • @DJBurb Aren’t arrow function and `function` function the wrong way around for this to work? – Sebastian Simon Aug 25 '21 at 01:51
  • @SebastianSimon—some time ago I ran a bit of a personal vendetta against calling *this* "context". Fortunately it's gone out of fashion (I likely had no effect on that, but I can bask in the halo). I just revert to type sometimes… :-) – RobG Aug 25 '21 at 02:17

1 Answers1

1

the scope and this value will be different even within the same function.

what happened? We created a new scope and did not trigger it in the event handler, so it gets the expected windows object. If we want this value not to be affected by the newly created scope, we can take some measures. As you may have seen before, we use that to create a cached reference to this and lexical binding So what we can do is.

var nav = document.querySelector('.nav');//<nav class="nav">

var toggleNav = function () {

var that = this;

console.log(that);//<nav> element

setTimeout(function () {

console.log(that);//<nav> element}, 1000);

};

nav.addEventListener('click', toggleNav, false); ```


  • 1
    The issue has nothing to do with scope. The value of *this* is set by the call, or lexcially in arrow functions. The issue is that *setTimeout* doesn't set the *this* of callbacks, so they default to the global object (window in a browser) or undefined in strict mode. @sebastianSimpon's comment to use *bind* is one (often the best) solution. Arrow functions and closures are another. – RobG Aug 25 '21 at 02:11