0

In a client-side only app, I'm loading two js files with script tags, one after another, and getting errors as appear in the comments below:

obj.js

'use strict';

let obj = {};

obj.func1 = () => {
  return 'stuff';
}

obj.func2 = (arr) => {
  debugger; // in devtools, value of 'this' is obj, as expected
  console.log(this); // clicking 'next' button in devtools,
                     // the object that is actually being printed to
                     // console is the window object!!!
                     // javascript, wtf?!?!
  debugger;

  let myStuff = this.func1(); // fails because window has no 'func1' property

  ...
  ...
}

window.obj = obj;

script.js

'use strict';

obj.func2()
// Uncaught TypeError: this.func1 is not a function

Why in the world does it happen? Why there's a difference in 'this' value between devtools debugger and actual result in the browser?

Edit:

See in the screentshot below how, when I'm executing console.log(this) myself in the console while being paused by the debugger break point, 'this' is Object(), and one step next (believe me that it's exactly one step next), window object is being printed to console.

enter image description here

BDL
  • 21,052
  • 22
  • 49
  • 55
Kludge
  • 2,653
  • 4
  • 20
  • 42
  • https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this – Creynders Apr 01 '16 at 16:15
  • Please attach a screenshot of this line: `debugger; // in devtools, value of 'this' is obj, as expected`. Why my devtool shows `this` is the `window` object? – stanleyxu2005 Apr 01 '16 at 16:34
  • @stanleyxu2005 IDK, I was able to repro in chrome beta (50) on linux mint and chrome canary (51) on OS X. What browser version/OS are you testing on? – Jared Smith Apr 01 '16 at 16:36
  • @JaredSmith I've attached a screenshot in my answer. I'm on Win7_x64 with Chrome 49. – stanleyxu2005 Apr 01 '16 at 16:42
  • @stanleyxu2005 per minusFour's comment, you're actually showing the problem in your screenshot :P – Jared Smith Apr 01 '16 at 16:45
  • 1
    This seems a duplicate of [What does “this” refer to in arrow functions in ES6?](http://stackoverflow.com/q/28371982/1529630). The debugger thing seems an unrelated browser bug. – Oriol Apr 01 '16 at 16:51
  • @Oriol disagree somewhat. Although the OP clearly did not understand what `this` is supposed to mean in arrow functions, it seems the *inconsistency* is what prompted the question. So I would say the browser bug is integral rather than unrelated. Just me $0.02 – Jared Smith Apr 01 '16 at 16:55
  • 1
    Related: [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/218196) . Also yes, there seems to be a bug in Chrome where it doesn't show the correct value for `this` in arrow functions. – Felix Kling Apr 01 '16 at 18:17

1 Answers1

2

The value of this in an arrow function is implicitly bound at the point of creation. Whatever this is in the context wherein the function is created will be the value of this when the function is invoked.

obj.func2 = (arr) => {
  // ...
};

is basically equivalent to

obj.func2 = function(arr) {
  // ...
}.bind(this);
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • so arrow functions aren't equivalent to 'regular' functions? – Kludge Apr 01 '16 at 16:15
  • 1
    @Kludge in this respect, no. They're like functions returned from `.bind()`. – Pointy Apr 01 '16 at 16:16
  • So why the values don't match between devtools and actual result? – Kludge Apr 01 '16 at 16:18
  • @Kludge which values don't match? What "devtools" are you talking about? – Pointy Apr 01 '16 at 16:18
  • See the 'debugger' break point. At that very moment, devtools shows that the value of 'this' *is* obj, like I expected – Kludge Apr 01 '16 at 16:19
  • 1
    Then the browser debugger is broken. What browser are you using? – Pointy Apr 01 '16 at 16:20
  • methinks should be `bind(obj)` instead `bind(this)` – Grundy Apr 01 '16 at 16:22
  • Are you using a transpiler, or native browser arrow functions? Transpilers don't usually rename variables for debugging well. – loganfsmyth Apr 01 '16 at 16:22
  • 2
    @Grundy it's OK that you think that but the language disagrees :) – Pointy Apr 01 '16 at 16:22
  • @loganfsmyth, no transpilers – Kludge Apr 01 '16 at 16:22
  • @Pointy, Doh! Your right! confuse with method _inside_ class – Grundy Apr 01 '16 at 16:23
  • @Pointy, Is there a way to use a more elegant, es6ish minimal way of writing functions, without the arrow function's default binding as you just explained? – Kludge Apr 01 '16 at 16:27
  • Able to reproduce bug, Chrome 50 on linux mint. – Jared Smith Apr 01 '16 at 16:28
  • The debugger isn't broken. The `this` you're viewing in the debugger is created ATM you're inspecting it, which _is_ `obj`. – Creynders Apr 01 '16 at 16:29
  • 1
    @Creynders that doesn't make sense. At that moment in the execution flow there's no implicit `this` binding in the arrow function, which means it goes up the scope chain. – Jared Smith Apr 01 '16 at 16:32
  • @Creynders I can't agree that this isn't a broken behavior. It's totally weird, sorry :P – Kludge Apr 01 '16 at 16:32
  • 2
    @Kludge No. if the `this` binding is important, then use `function`. Arrow functions are useful for things where you want the outer `this` like event handlers and returning functions from functions. They weren't meant as a drop-in replacement for `function`. – Jared Smith Apr 01 '16 at 16:33
  • btw, @Pointy, thanks for your help, meanwhile I'm using `obj` instead of `this`, to avoid the bind change. I'm leaving the question not answered in order to see if I can get clearer answer regarding the bad status devtools reports, IMHO – Kludge Apr 01 '16 at 17:05