Free email newsletter: “ News


Why is (0,obj.prop)() not a method call?

This blog post explores references, a mechanism used by the ECMAScript language specification to explain the difference between the following two expressions:

    (0, obj.prop)()

Method calls versus function calls

Consider the following object:

    var obj = {
        getThis: function () {
            "use strict";
            return this;

If you call obj.getThis, you have a method call (this points to the object in which the method is stored):

    > obj.getThis() === obj

If you store obj.getThis in a variable and then call it, you are making a function call:

    > var func = obj.getThis;
    > func()

The effect is the same if you use the comma operator. Quick recap – the comma operator works like this:

    (expr1, expr2) === expr2

That is, both expressions are evaluated, the result of the whole expression is expr2.

If you apply the comma operator to obj.getThis before calling it, you are also making a function call:

    > (0,obj.getThis)()

What the first operand is doesn’t matter at all, here, I use 0, because its short. I’d expect many JavaScript engines to optimize and eliminate the evaluation of the first operand.

However, only using parentheses does not change anything:

    > (obj.getThis)() === obj

So what is going on? The answer has to do with references.

References, a data structure of the ECMAScript spec

References are a data structure that is used internally by the ECMAScript language specification. A reference has three components:

  1. Base value: is either undefined, a primitive value, an object or an environment record. undefined means that a variable name could not be resolved. Accessed via GetBase(V) (given a reference V).
  2. Referenced name: is a string or a symbol. Accessed via GetReferencedName(V) (given a reference V).
  3. Strict reference: flag indicating whether or not the reference was created in strict mode. Accessed via IsStrictReference(V) (given a reference V).

Examples of JavaScript expressions that produce references:

  • Property reference: Evaluating obj.prop in strict mode produces the reference (obj, 'prop', true).
  • Identifier reference: Evaluating foo in strict mode produces the reference (env, 'foo', true). env is the environment record where the variable foo is stored.

The flag for strict mode is necessary, because some operations cause an exception in strict mode, but fail silently in sloppy mode. For example: setting an unresolved variable in sloppy mode creates a global variable, setting it in strict mode throws a ReferenceError.

These are two operations (of several) for references:

  • GetValue(V) if V is a value, the result is V. If V is a reference, the result is the value pointed to by the reference. This conversion from reference to referenced value is called dereferencing.
  • PutValue (V, W) writes the value W to the reference V.
  • GetThisValue(V) is only called if V is a property reference. For normal references, it returns the base value. For references created via super, it returns the additional component thisValue that they have (which is needed for super property references).

References in the example

We are now ready to understand the examples we looked at earlier.

The following expression produces a reference:


If you function-call this reference ref then this is set to GetThisValue(ref).

If you wrap obj.getThis in parentheses, nothing changes, parentheses only syntactically group things, but the don’t influence how something is evaluated. That is, the result of the following expression is still a reference:


If, however, you assign the reference returned by obj.getThis to a variable, the reference is dereferenced:

    var func = obj.getThis;

In other words: what is stored in func is a function, not a reference. In the language spec, assignment operators use GetValue() to turn references into values.

The comma operator also dereferences its operands. Consider this expression:

    (0, obj.getThis)

The comma operator`) to ensure that the result of each operand is dereferenced if it is a reference.

References and bind()

References only being temporary is also the reason why you need to use bind if you want to turn a method into a callback (first line):

    var log = console.log.bind(console);

If you simply did:

    var log = console.log;

Then the receiver (this) would get lost, because console.log is dereferenced before it is stored in log.

References in real-world code

Babel uses the comma operator to avoid function calls being transpiled to method calls.

Consider, for example, this ES6 module:

    import assert from 'assert';

Babel compiles it to this ES5 code:

    'use strict';
    function _interopRequireDefault(obj) {
        return obj && obj.__esModule
            ? obj
            : { 'default': obj };
    var _assert = require('assert');
    var _assert2 = _interopRequireDefault(_assert);
    (0, _assert2['default'])(true); // (A)

Why does the ECMAScript language specification use references?

JavaScript engines, which are implementations of the ECMAScript language specification, don’t actually use references. That means that they are a device that helps with writing the spec. To see why, consider that they represent storage locations. Then consider that all of the following operations work with storage locations:

  • Reading a value:

  • Calling a function or a method:

  • Assigning a value:

        x = 123
        obj.prop = 123
        super.prop = 123
        obj["prop"] = 123
  • Compound assignment operators. For example, the addition assignment operator (+=):

        x += 5
        obj.prop += 5
        super.prop += 5
        obj["prop"] += 5
  • typeof:

        typeof x
        typeof obj.prop
        typeof super.prop
        typeof obj["prop"]
  • delete:

        delete x
        delete obj.prop
        delete super.prop
        delete obj["prop"]

Because each storage location is represented by the same construct, a reference, the specification only needs to describe a single version of each operation instead of several versions (e.g.: delete for a variable, delete for a property with a fixed key, delete for a property with a dynamically computed key, etc.).


You don’t actually see references when you use JavaScript. But there are languages (e.g. Common Lisp) where references are first class values. That enables intriguing applications. You can, for example, implement functions that perform an assignment for you.

No comments: