Given that a variable declared with const
cannot be reassigned or deleted see
why is it possible to reassign a value to a variable declared with const
within a function passed to .then()
chained to Promise.resolve()
where const
variable is passed, but it is not possible to reassign the const
variable with function passed to .then()
chained to Promise
constructor where const
variable is passed to resolve()
parameter of Promise
constructor resolver
function?
"use strict"
const state = "123";
Promise.resolve(state)
.then(state => {
console.log(state); // `"123"`
state = 456; // reassign `const` variable `state` to `"456"`
return state
})
.then(state => console.log(state)) // `"456"`
// not reached
.catch(err => console.error(err.message));
{
"use strict";
const state = "123";
new Promise(resolve => {
console.log(state); // `"123"`
state = "456"; // reassign `const` variable `state` to `456`
resolve(state);
})
.then(state => {
console.log(state);
})
// `Error: Assignment to constant variable.`
.catch(err => console.error(err.message));
}
Edit, Updated
To clarify the basis and motivation for the inquiry, the Question is an attempt to determine when an identifier can be used which is the same as a const
declaration, and when that procedure is not possible. In essence, trying to create an identifier which throws an error in any scope where an attempt is made to assign the identifier a different value - whether function scope, block scope or anywhere in the code - a "superconst
" indetifier, or the closest to that description currently possible, depending on the engine. Are Map
or WeakMap
or class
the closest we currently have at newest browser implementations?
Here constant
state
variable is not changing. You are changing the parameter value which is passed to the resolve function. You can verify this by simply doingconsole.log(state)
after all your code and output will be123
.You are not assigning to the
const
variable. You are instead assigning to the function parameter that you gave the same name. That function parameter is a non-const copy of the variable so you are allowed to assign to it.I will try to collect all my comments into a more fully explained answer.
In code here:
First, you define your
const state = "123"
variable. Any attempt to change the contents of that exactstate
variable will throw an exception.Then, when you do this:
That declares a
.then()
handler function that takes one argument and the name of that argument isstate
. When the.then()
handler is called, whatever is passed as that one argument to the.then()
handler is copied into this new argument variable namedstate
. Function arguments are notconst
. They can be assigned to.Because you've now created TWO separate variables with the same name and one is at a higher scope, when you are inside the
.then()
handler, that function argument namedstate
"overrides" or "hides" the other variable of the same name. When you attempt to accessstate
inside the.then()
handler, the ONLY variable you can access when using that name is the function parameter. That function parameter is a copy of the other state variable by virtue of being passed to the.then()
handler as an argument. All function arguments are copies. Javascript has no true reference variable types.Furthermore function arguments are not
const
so you can assign to them.So, when you
state = "456";
inside that.then()
handler, you are just assigning to the function argument. Because you've created a naming conflict, there is actually no way to access the higher scopedconst state
variable. The JS interpreter finds the definition that is closest in scope to where you are attempting to access it.I think your confusion will be cleared up if you just stop creating a conflicting variable name. If you do it like this (name the parameter
localState
):Then, you will see an exception when you attempt to assign to
state
because you have not created a conflicting local variable with that same name so your attempt to assignstate = 456
will indeed be attempting to assign to aconst
variable and the interpreter will object.As best I know, Javascript has no way to prevent overriding a higher scoped variable with a newly declared variable of the same name in the local scope. That just isn't a language feature. When the interpreter resolves a variable name, it searches the scope hierarchy from local to global so local definitions are found (and used) first. Higher scoped definitions are "overriden" or "hidden" within that scope. That's just how they designed variable name resolution to work in the language.
There are many benefits to this too in that somebody suddenly declaring a higher scoped variable that you aren't using or aren't even aware of will never accidentally break your lower scoped declarations. When you yourself declaring a conflict and you actually want to use the higher scoped named, that's just a coding mistake. You have to not declare a conflicting name if you intend to use the higher scoped variable of the same name.