I'm implementing a JavaScript interpreter, and I can't figure out the details of binding functions to objects in JavaScript.
A rudimentary example:
const o = {
x: 1,
getX: function() {
return this.x;
}
};
o.getX(); // returns 1
The tricky part is what happens when you assign getX
to a variable:
let gX = o.getX;
gX(); // returns undefined
My question is: how does the runtime know that o.getX()
gets bound to o
, but gX()
should be unbound? I would assume gX
and o.getX
are pointing to the exact same function!
I first thought that maybe the presence of the .
is what makes the difference. So, in the grammar, there's a production like <method-call> ::= <expr> '.' ID '(' <expr>* ')'
, and this expression is treated differently (the result of evaluating the first <expr>
is bound to the function found under ID
) than a "regular" call (without a .
).
But the following expression seems to disprove this theory, because (o.getX)()
also returns 1
. However, in some magical way, (gX = o.getX)()
returns undefined
, even though it's clear to me the assignment expression returns its right-hand size, so o.getX
in this case!
Is there a simple explanation of how these semantics are implemented? I can't figure out a way that my runtime is supposed to differentiate that o.getX
is bound to o
, but gX
, even though it's pointing at o.getX
, is not bound.