Why is the named IIFE logged instead of the variable with the same name?
Asked Answered
P

1

16

I saw the code below that someone posted. I’m confused about what it logs. It logs the function a, not 200. Why?

var a = 1;
(function a() {
  a = 200;
  console.log(a)
})()
Penley answered 4/7, 2019 at 7:1 Comment(1)
If anyone is wondering what is IIFE? then its Immediately Invoked Function Expression or Self-Executing Anonymous FunctionGastrostomy
H
23

Because the function being immediately invoked is named, and that name cannot be reassigned to refer to something else directly inside the IIFE.

Any named function expressions will exhibit this behavior as well. A function expression whose function is named a will mean that a directly inside the function will always refer to the function itself, even if you try to reassign it.

You can make the error explicit if you use strict mode:

'use strict';
var a = 1;
(function a() {
  a = 200;
  console.log(a)
})()

Uncaught TypeError: Assignment to constant variable.

Having a named function expression is a bit like having

(function a() {
  const a = <this function>;
  // ...
})()

except trying to reassign it will only throw in strict mode.

Specifically, I believe the ECMAScript 5 specification for this behavior is in SetMutableBinding:

  1. If the binding for N in envRec is a mutable binding, change its bound value to V.
  2. Else this must be an attempt to change the value of an immutable binding so if S (strict mode being used) if true throw a TypeError exception.

But directly inside a function, the function name binding is not mutable - see Function Definition:

The production

FunctionExpression : function Identifier ( FormalParameterListopt ) { FunctionBody }

is evaluated as follows:

Call the CreateImmutableBinding concrete method of envRec, passing the String value of Identifier as the argument.

Human answered 4/7, 2019 at 7:4 Comment(2)
Could you point to some specs about this behavior. For one, I suspect it doesn't need to be "Immediately Invoked", setTimeout((function a() { a = 200; console.log(a) }), 1000) would act the same.Whitehall
Got it, it's here and as suspected, it applies to all named FunctionExpressions, not only ImmediatelyInvoked ones (which I don't think are a thing in the language, just a usage)Whitehall

© 2022 - 2024 — McMap. All rights reserved.