您没有分配给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()
handler,使用该名称时可以访问的唯一变量是函数参数。该函数参数是另一个状态变量的副本,因为它被传递给.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 无法阻止使用本地作用域中新声明的同名变量覆盖更高作用域的变量。这不是语言功能。当解释器解析变量名时,它会从本地到全局搜索范围层次结构,因此首先找到(并使用)本地定义。更高范围的定义在该范围内被“覆盖”或“隐藏”。这就是他们设计变量名称解析以在该语言中工作的方式。
这样做也有很多好处,因为有人突然声明您没有使用或什至不知道的较高作用域变量永远不会意外破坏您的较低作用域声明。当您自己声明冲突并且实际上想要使用更高范围的命名时,这只是一个编码错误。如果您打算使用同名的更高范围的变量,则不必声明冲突的名称。