Ответ 1
Вы не назначаете переменную const
. Вместо этого вы назначаете параметр функции, который вы дали тому же имени. Этот параметр функции является неконстантной копией переменной, поэтому вам разрешено назначать ей.
Я попытаюсь собрать все мои комментарии в более подробный ответ.
В коде здесь:
"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));
Сначала вы определяете свою переменную const state = "123"
. Любая попытка изменить содержимое этой точной переменной state
вызовет исключение.
Затем, когда вы это сделаете:
Promise.resolve(state).then(state => {
Это объявляет функцию обработчика .then()
, которая принимает один аргумент, а имя этого аргумента - state
. Когда вызывается обработчик .then()
, все, что передается, поскольку этот аргумент обработчику .then()
копируется в эту новую переменную аргумента с именем state
. Аргументы функции не const
. Они могут быть назначены.
Поскольку теперь вы создали две отдельные переменные с одним и тем же именем, и один находится в более высокой области видимости, когда вы находитесь внутри обработчика .then()
, этот аргумент функции с именем state
"переопределяет" или "скрывает" другой переменная с тем же именем. Когда вы пытаетесь получить доступ к state
внутри обработчика .then()
, ТОЛЬКО переменная, которую вы можете получить при использовании этого имени, является параметром функции. Этот параметр функции является копией другой переменной состояния в силу передачи в обработчик .then()
в качестве аргумента. Все аргументы функции - это копии. Javascript не имеет настоящих ссылочных типов переменных.
Кроме того, аргументы функции не const
, поэтому вы можете назначить им.
Итак, когда вы state = "456";
внутри этого обработчика .then()
, вы просто назначаете аргумент функции. Поскольку вы создали конфликт имен, на самом деле нет способа получить доступ к переменной с расширенным охватом const state
. JS-интерпретатор находит определение, которое ближе всего к области, где вы пытаетесь получить к ней доступ.
Я думаю, что ваша путаница будет устранена, если вы просто прекратите создавать конфликтующее имя переменной. Если вы сделаете это так (назовите параметр localState
):
"use strict"
const state = "123";
Promise.resolve(state).then(localState => {
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));
Затем вы увидите исключение при попытке назначить state
, потому что вы не создали конфликтующую локальную переменную с таким же именем, чтобы ваша попытка назначить state = 456
действительно пыталась назначить const
, и интерпретатор будет объективом.
Насколько я знаю, Javascript не имеет возможности предотвратить переопределение переменной с более высокой областью с новой объявленной переменной с тем же именем в локальной области. Это просто не язык. Когда интерпретатор разрешает имя переменной, он ищет иерархию областей с локального на глобальное, поэтому локальные определения сначала обнаруживаются (и используются). Определения с более высокой степенью охвата "переопределены" или "скрыты" в пределах этой области. Это то, как они разработали разрешение имен имен для работы на языке.
В этом есть много преимуществ, потому что кто-то внезапно объявляет более высокую область видимости, которую вы не используете или даже не подозреваете, никогда не случайно сломает ваши объявления с более низким охватом. Когда вы сами объявляете конфликт, и вы действительно хотите использовать имя с более высоким охватом, это просто ошибка кодирования. Вам не нужно объявлять конфликтующее имя, если вы намерены использовать переменную с более высокой областью с тем же именем.