It's the same as this
where the object initializer is. So in both of your examples, it's the same as this
where your var a = ...
line is. this
never changes within a given execution context, and object initializers don't create a new execution context; only functions and eval
do that. In your examples, the only time a new execution context is created is when you call fn
, and since fn
is an arrow function, it closes over the this
in the execution context where it was created (which happens to be the global execution context in your examples).
The reason you see 100
for this.c
in your example code is that this
at global scope (in loose mode) refers to the global object, and var
variables at global scope become properties of the global object, and so this.c
is the c
global variable.
If you put all of that code in a scoping function, like this:
(function() { // Or `(() => {`, doesn't matter in this case
var c = 100;
var a = {
c: 5,
b: {
c: 10,
fn: ()=> {return this.c;}
}
}
console.log(a.b.fn());// still 100, why not 5?
})();
...this.c
would be undefined
, because although this
would still refer to the global object, c
would no longer be a global variable (and thus a property of the global object).
If you want this
inside fn
to refer to b
in the expression a.b.fn()
, then you don't want an arrow function there, you want a normal function; you'd get 10
(the value of a.b.c
), not 5
(the value of a.c
).
Of course, as this is a one-off object and fn
closes over a
, you can also just make fn
's body return a.c;
or return a.b.c;
depending on which c
you want.