Question 30 / 31
Does nesting an object one level deeper change how this resolves?
Topic: this bindingDifficulty: Advanced
A method reached through person1.obj.foo1() still resolves this from the call site — the extra layer of property access does not add a receiver of its own.
Solve it with the execution visualizerStep through every binding, function call, and console output below.Predict the output
Person builds this.obj as a nested object with two methods, each returning an inner function. Predict all six console lines.
var name = "Window";
function Person(name) {
this.name = name;
this.obj = {
name: "Obj",
foo1: function () {
return function () {
console.log(this.name);
}
},
foo2: function () {
return () => console.log(this.name)
},
}
}
var person1 = new Person("Person1");
var person2 = new Person("Person2");
person1.obj.foo1()();
person1.obj.foo1.call(person2)();
person1.obj.foo1().call(person2);
person1.obj.foo2()();
person1.obj.foo2.call(person2)();
person1.obj.foo2().call(person2);Reveal the answer and explanation
Expected output
Window
Window
Person2
Obj
Person2
ObjWhy this happens
obj.foo1 returns a plain (non-arrow) function. person1.obj.foo1()() and person1.obj.foo1.call(person2)() both call that returned function bare, so default binding applies regardless of how foo1 itself was invoked — both print "Window".
person1.obj.foo1().call(person2) then explicitly calls the returned function with person2 as this, printing "Person2".
obj.foo2 returns an arrow, created fresh every time foo2 runs and closing over whatever this was for that foo2 call. person1.obj.foo2()() calls foo2 as a method off obj — implicit binding makes this = obj for that call, so the arrow closes over obj and prints "Obj".
person1.obj.foo2.call(person2)() explicitly forces this = person2 for the foo2 call itself, so this time the returned arrow closes over person2 and prints "Person2". person1.obj.foo2().call(person2) calls foo2 as a method again (this = obj, same as the first foo2 call), so the returned arrow still closes over obj — calling .call(person2) on that finished arrow changes nothing, printing "Obj" again.
What this question tests
- implicit binding always looks at the object immediately to the left of the dot at the call site — person1.obj.foo2() binds this to obj, not to person1
- nesting a property one level deeper does not change any of the four binding rules — it just moves where the "object to the left of the dot" is read from
- the arrow inside obj.foo2 is re-created on every foo2() call, so each call can capture a different this — unlike a method assigned once in a constructor
Runtime assumptions
Assumes a classic sloppy-mode script; new Person(...) supplies the constructor call’s this per the [[Construct]] semantics used elsewhere in this series.