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?
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?
-
3
counter
isn't incremented. It's passed by value -- not reference -- to theincrement
function. Examineconst counter
's value after theincrement
function has been called and you'll see that it hasn't changed. I think we can both agree that, eg, literal1
is constant. As a thought experiment, what happens when you callincrement(1)
? Do all the1
s in your source code turn into2
s? – Kelvin Sherlock Commented Feb 5, 2018 at 3:08 -
Your code example won't even increment the original
counter
variable in actual ES6 because of the pass by value, not reference (which means a non-const copy ofcounter
is what is passed to the function. You can't make function parametersconst
either. So, this has nothing to do with Babel. This is how Javascript works. – jfriend00 Commented Feb 5, 2018 at 4:33 -
The title of your question is a wrong assertion about how passing arguments work in Javascript. You appear to be thinking that passing a
const
variable as a function argument will "retain" theconst
for that function parameter. Javascript does not do that. Function parameters are copies or pointers. They aren't the originalconst
variable. – jfriend00 Commented Feb 5, 2018 at 5:11 -
All parameters are always passed by value in Javascript. For primitives (
Number
,String
,Boolean
) this means the value is copied. So whatever you do with the (copied) value inside the function will have no effect on the value that the caller passed in. When you pass an object or an array to a function, the parameter is still passed by value, but those values are actually references (like, but not quitte the same as, pointers), meaning they just contain a reference to the actual object, which lives on the heap. – Stijn de Witt Commented Jan 14, 2019 at 8:07
2 Answers
Reset to default 8Counter is declared const, still it can be changed!
There are two identifiers with name counter
in the transpiled code:
- The parameter
counter
insideincrement
. - The variable
counter
insidetest
.
They are pletely 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).
There are two things going on here:
- The function is passing the
value
of your variable and not the variable itself (as other answers have explained) - The way in which babel transpiles
const
tovar
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;
// bees
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;
// bees
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.