Search code examples
javascriptglobalshared-memoryiifeuse-strict

Why does this code create the object, but still treats it as undefined?


I don't understand why doesn't this code work as expected:

"use strict";
window.obj.prop = (() => {
    window.obj = { myobj: true };

    return "value";
})();

enter image description here

I always thought that = operator first evaluates whatever it is to the right of it (IIFE in this snippet), and then assigns the result to whatever is to the left of it (window.obj.prop in this snippet). Looks like something different happens here though.

If the interpreter first evaluates the IIFE, then it should create window.obj before setting its .prop, which shouldn't result in TypeError. On the other hand, if the interpreter first checks presence of prop in window.obj (and fails with TypeError because window.obj is undefined), then it shouldn't evaluate the IIFE, which shouldn't create window.obj.

What I observe is that both window.obj is created and TypeError is thrown, which doesn't make sense to me.


Notes:

  • "use strict" thrown in "just in case", the snippet works similarly without it;
  • the snippet works the same both in browser (Chrome 80.0) and Node.js (v13.3);
  • the window.obj (or global.obj in Node) object doesn't exist prior to this snippet being run;

Solution

  • I was wrong. This should throw an exception even before evaluating the rhs. It's a bug (or at least, deviation from the spec) in the engine. See https://es.discourse.group/t/rhs-evaluation-in-assignment-to-unresolvable-reference/310.


    That's just how it works:

    1. The left-hand side is evaluated to a reference
    2. The right-hand side is evaluated to a value
    3. The value is put in the reference, which throws an error if the reference cannot resolve its base value

    I don't know why they didn't bother checking the reference before evaluating the right-hand side, however this behaviour is consistent with a setter property throwing.