2

[UPDATE]: It turns out there are tow reason for my question:

For CAN NOT: It is my lack of knowledge about how arrow function works, it just locks the surrounding context everywhere it defined. And the global is undefined in strict mode.

For CAN: It could be a bug of old version Chrome Dev Tool.

Please refer to comment to find out what are the CAN and CAN NOT here


All:

I am pretty new to ES6, when I try arrow function's concept of lexical context locking, I use code like:

var glb = {name: "glb" };
glb.showname = () => {
    /******* interesting thing happens here below *******/
    console.log(this);
    this.name = "hello"
    return () => {
        console.log(this.name);
    }
}
const ext = {name: "ext"};
ext.showname = glb.showname();
ext.showname();

And I transpile it with:

browserify main.js  -o bundle.js -t [ babelify --presets [ es2015 ]   ] -d

Interesting thing is:

When I run it without setting breaking point(either with Node or in Chrome), it always give me error:

Uncaught TypeError: Cannot set property 'name' of undefined

and the console just prints out undefined

But when I set a break point(I do it in Chrome), this time, the context can be printed out like:

 Object {name: "glb"}

Any idea why this happens?

Thanks

Kuan
  • 11,149
  • 23
  • 93
  • 201
  • 3
    That's because the lexical scope at the global level is `undefined`. An arrow function will *always* use it's lexical scope, not the object which calls it. – Mike Cluck Mar 22 '16 at 17:05
  • @MikeC Thanks, so this is a bug of Chrome that it accidentally assign the glb as context to `this` in arrow function block? And how can I define arrow function which use context of glb? – Kuan Mar 22 '16 at 17:08
  • 1
    It's a bug if it reports `this` as `glb`, yes. You can't use arrow functions to define a method on `glb` because it will always refer to the surrounding scope. – Mike Cluck Mar 22 '16 at 17:09
  • 1
    Sounds like the dev tools are not yet up-to-date. – Bergi Mar 22 '16 at 17:16
  • @Bergi Thanks. Yes, my chrome is old, it is Version 48.0.2564.109 – Kuan Mar 22 '16 at 17:17
  • @MikeC Thanks, so basically the only way to pass context in for the top level function definition is to use traditional ES5 syntax? And most ES6 code will be like this pattern: `function(){ ()=>{} }` ? – Kuan Mar 22 '16 at 17:25
  • @Kuan You could use [method syntax.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions) `glb = { name: 'glb', showname() { ... } }`. – Mike Cluck Mar 22 '16 at 19:13
  • Possible duplicate of [Getting this as undefined when using arrow function ](https://stackoverflow.com/questions/37182473/getting-this-as-undefined-when-using-arrow-function). There is no bug in the devtools: the issue is that you are transpiling your code, and the `this` in your ES6 source code is different from the `this` in the actually executed code - that you will also see when entering `this` in the console. – Bergi Oct 12 '18 at 16:16

1 Answers1

4

If the Chrome dev tools are reporting this to be glb then there is a bug in the tools, which isn't too surprising given how new arrow functions are. this should be equal to undefined, as stated in your error.

Arrow functions bind to their lexical scope and only their lexical scope. Meaning, regardless of what object the function is attached to, it will always be called with the original lexical scope. This code shows a few examples of how arrow functions work.

var globalScope = () => {
  console.log(this); // undefined
};

function MyObj() { // Assuming we use it as a constructor
  console.log(this); // MyObj
  this.myObjScope = () => {
    console.log(this); // MyObj
  };
}

MyObj.prototype.globalScope = () => {
  console.log(this); // undefined
};

For a detailed rundown on arrow functions, see this Stack Overflow answer.

Community
  • 1
  • 1
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • Thanks, but why that `this` is NOT `Window` object but undefined inside globalScope function? – Kuan Mar 22 '16 at 17:13
  • 2
    @Kuan Because all ES6 code runs in strict mode and [global `this` is `undefined` in strict mode](https://jsfiddle.net/6zkyp95q/). [Read here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) for more information. – Mike Cluck Mar 22 '16 at 17:15
  • 1
    Thanks, now I get it! – Kuan Mar 22 '16 at 17:15
  • This answer is basically a duplicate of http://stackoverflow.com/questions/34361379/arrow-function-vs-function-declaration-expressions-are-they-equivalent, explaining why it's undefined. Please instead answer the question that the reporting of `this` is buggy. – Bergi Mar 22 '16 at 17:17
  • 2
    @Bergi Good find. I added information explaining why it's a bug in the tools. – Mike Cluck Mar 22 '16 at 17:20
  • 1
    @MikeC You aren't quite correct, all ES6 code does not run in strict mode, code processed as an ES6 module is always in strict mode, and as an unrelated fact `this` inside an ES6 module is `undefined`. `this` inside an arrow function always inherits the parent, so if the arrow is in a module, `this` is `undefined`, but if the arrow were in a – loganfsmyth Mar 22 '16 at 18:00
  • @loganfsmyth Good point. I incorrectly conflated module scoping with all ES6 scoping since it tends to be compiled that way. Thanks for the correction. – Mike Cluck Mar 22 '16 at 19:11