Aamir Maniar
Aamir Maniar

Reputation: 1

Why does Babel not properly handle const?

Check it out following code. The counter is declared as const. When you run it, it should not allow it to change in any situation!

function increment(counter) {
 counter += 1; 
}

function test() {
    const counter = 1;
    increment(counter);
}

When transpiled, it produces the following code. Which allows const counter to be incremented!

function increment(counter) {
  counter += 1; // Counter is declared const, still it can be changed!
}

function test() {
  var counter = 1;
  increment(counter);
}

I'm just trying to understand, whether it is a problem with Babel transpilation or with JavaScript specification.

Edit: I know that unlike ES6, the current version of JS does not support const. My concern is, if I use transpiled JavaScript, I may encounter unknown const related bug. Should that be okay?

Upvotes: 0

Views: 2938

Answers (2)

Felix Kling
Felix Kling

Reputation: 816462

Counter is declared const, still it can be changed!

There are two identifiers with name counter in the transpiled code:

  • The parameter counter inside increment.
  • The variable counter inside test.

They are completely independent!

Parameters are never "constant", they can always be assigned a new value. It has no impact on what you passed to the function, since all arguments are passed by value, i.e. increment is passed the value of the variable counter which is then assigned to the parameter counter.

We can easily verify this by logging the value of the variable before and after the function call:

function increment(counter) {
 counter += 1; 
}

function test() {
    var counter = 1;
    console.log('value before', counter);
    increment(counter);
    console.log('value after', counter);
}

test();

I'm just trying to understand, whether it is a problem with Babel transpilation or with JavaScript specification

With neither. It works exactly has specified, no matter whether you are using var or const to declare counter.

My concern is, if I use transpiled JavaScript, I may encounter unknown const related bug.

No, that won't be the case. What makes const special? That you cannot assign a new value to it and that it is blocked scoped. So lets have a look what Babel does when you are violating these two constraints:

Input:

const foo = 21;
foo = 42;

Babel output:

Babel refuses to transpile the code with the error

SyntaxError: intput.js: "foo" is read-only
  1 | const foo = 42;
> 2 | foo = 21;
    | ^
  3 |

Input:

{
  const foo = 21;
}
console.log(foo); // trying to access const outside of block

Babel output:

"use strict";

{
  var _foo = 21;
}
console.log(foo); // trying to access const outside of block

Babel renamed the block-scoped variable. foo doesn't exist (as expected).

Upvotes: 8

coagmano
coagmano

Reputation: 5671

There are two things going on here:

  1. The function is passing the value of your variable and not the variable itself (as other answers have explained)
  2. The way in which babel transpiles const to var and still keeps the contract of not being re-assignable. I'll explain this part in my answer:

Why does Babel does not properly handle const?

The thing about babel and const, is that it only works via static analysis

The transpilation of working code converts const into var as that's all that exists in ES5.

const a = 0
const b = a + 1;
// becomes
var a = 0;
var b = a + 1;

The magic happens when babel finds you assigning a different value to your variable like so:

const a = 1;
a = a + 1;
// becomes
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }

var a = 1;
a = (_readOnlyError("a"), a + 1);

Because babel can tell it will throw an error by reading your code, it replaces the point where the error happens with an error.

So in effect for 99% of cases, const prevents re-assignment when converted to ES5.

Ergo Babel does properly handle const

The reason why your code wasn't transpiled to throw an error is because of part 1.

Upvotes: 1

Related Questions