Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nature of JS bound functions and function invocation operator

Tags:

javascript

oop

var obj = {};

var r1 = (obj['toString'])();
var m1 = obj['toString'];
var r2 = m1();

var r3 = (obj.toString)();
var m2 = obj.toString;
var r4 = m2();

r1 and r3 expectedly contain correct result: "[object Object]", while r2 and r4 contain "[object Undefined]" showing that m1 and m2 are not bound to object.

I can't fully comprehend how obj['toString']() is executed. I always looked this way, (obj['toString'])() -> (function obj)(). Turns out that function invocation operator looks back on what is the context. I would expect operator to not know where operands come from.

Can anyone properly explain this behavior?

like image 882
Andrey Avatar asked Feb 13 '23 03:02

Andrey


2 Answers

Turns out that function invocation operator looks back on what is the context. I would expect operator to not know where operands come from.

In fact, it does know.

In the EcmaScript specification this is described by the property accessor operators (and a few similar operations) to return a "Reference object" that holds exactly this information: the context on which the property was accessed. Any "normal" operations will usually just get the reference's value - including the assignment operators, which do dissolve the reference in your case.

The call operator uses this to make method calls special:

  1. Let ref be the result of evaluating MemberExpression. which may return a Reference
  2. Let func be GetValue(ref). which fetches the actual function object - you see this operation a lot in the spec
  3. fetch arguments, do some type assertions
  4. If Type(ref) is Reference, then
    • If IsPropertyReference(ref) is true, then
      Let thisValue be GetBase(ref). <- here the method context is fetched
    • Else, the base of ref is an Environment Record
      which basically describes variables inside a with statement
  5. Else, Type(ref) is not Reference.
    Let thisValue be undefined.
like image 102
Bergi Avatar answered Feb 14 '23 16:02

Bergi


This is actually a "special" behavior of the grouping operator (...):

1. Return the result of evaluating Expression. This may be of type Reference.

NOTE This algorithm does not apply GetValue to the result of evaluating Expression. The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesised expressions.

So, this operator specifically does not call GetValue and thus does not return the function object itself but rather the whole reference, so that operations which expect a reference still work.


A Reference is basically an encapsulation of a value with an optional "base value" which is the object in case of a property access.

like image 32
Felix Kling Avatar answered Feb 14 '23 15:02

Felix Kling