4
  1. var a = function b() {
        b = 123;
        console.log(b === window.a)  // true
        console.log(b)    // function b() { ... }
    }
  2. function a() {
       a = 3;
       console.log(a)    // 3
    }

Why is the variable b not changeable, what is it?

Travis J
  • 81,153
  • 41
  • 202
  • 273
keyao Hou
  • 59
  • 2
  • Interesting, so function name bindings are not reassignable inside their function. If you use `use strict`, you get `Uncaught TypeError: Assignment to constant variable.`. (but that's not the same thing as a `const`) – CertainPerformance Oct 24 '18 at 07:54
  • I'm more concerned with the form of the function name b in memory. – keyao Hou Oct 24 '18 at 08:19
  • 1
    You have one question in the title, two questions in the post body and one question in your comment. All of them are already answered somewhere. It would help you to receive more helpful answers (or duplicate close votes) if you split your question in separate posts. – GOTO 0 Oct 24 '18 at 08:23

1 Answers1

2

There are two types of locals in Javascript. These are

  • Declared locals: When you declare a local variable by using one of the keywords (e.g. var, const, let), these variables are determined as declared. In non-strict mode, your variable declaration falls back to var.
  • Artificial locals: When you declare a function using the function declaration syntax, you actually declare an artificial local with the name of the function. For example, function foo() {} defines an artificial local named foo.

JavaScript handles these two types of locals differently in terms of variable hoisting. Declared locals need to be reached to the declaration (or their first usage) to be referenced. On the other hand, artificial locals are hoisted to the initial scope state, hence it is usable from the start of the scope.

You may consider this code:

bar();      // prints 'bar' on the console
foo();      // error: 'undefined' is not callable

const foo = function () {
  console.log('foo');
}

function bar() {
  console.log('bar')
}

bar();      // prints 'bar' on the console
foo();      // prints 'foo' on the console

In your example, your a = 3 statements mutate declared local in the outer scope, overriding your old artificial local declared as a side-effect of your function declaration. Since you are using non-strict mode, it is pretty hard to see the difference, however, you may think about your implementations like so:

var a_dec = function b_art () {
  b_dec = 123;
  console.log(b_art === window.a_dec);
  console.log(b_art);
}

function a_art () {
  a_dec = 3;
  console.log(a_dec);

  // when you run this, b_art is not reachable with a_dec anymore
}

This is an implementation detail. Here, the artificial variable declaring the function takes precedence over the declared local. The a is declared as a declared variable for the first time, so it is counted as it is. The matter of being a declared variable makes it mutable, in contrast to the artificial variables.

Buğra Ekuklu
  • 3,049
  • 2
  • 17
  • 28