References (Continued)
JavaScript Corners – Part 8
References (Continued)
Given an object o with a member function f that prints out what the this value is:
const o = { f() { console.log( this === global ? 'global' : this === undefined ? 'undefined': this === o ? 'o': '-'); } }
We know what the following prints:
o.f(); // prints "o"
And we know what the following prints1:
const f = o.f; f(); // prints "global"
I always thought that the difference came down to the fact that o.f() is actually invoking a different operator — something like a “member call operator”.
However, what do you think the following prints?
(o.f)();
My guess, up until today, would have been that this prints “global”, since with the parentheses, this is no longer invoking the member call operator, but is instead invoking the call operator.
But I was wrong. There is no such thing as a “member call operator”. Rather, the “call” operator just behaves differently depending on whether the target of the call is a value or a reference2.
So this actually prints “o”.
(o.f)(); // prints "o"
But hang on. Why didn’t the parentheses coerce o.f to a value?
One might have expected the parentheses to automatically dereference o.f, something like the following examples that use the logical OR and comma operators to coerce the target to a value instead of a reference:
(o.f || 0)(); // prints "global" (0, o.f)(); // prints "global"
Indeed, this could have been the case for bare parentheses as well, but the language designers chose not to do it that way, so that the delete and typeof operators still work when extraneous parentheses are provided:
delete o.f; // The "correct" way to delete a property delete (o.f); // This also works
One Reply to “JavaScript Corners – Part 8
References (Continued)”