为什么.then()链接到Promise.resolve()允许重新分配const声明?

时间:2017-07-28 19:01:37

标签: javascript scope ecmascript-6 promise const

鉴于用const声明的变量无法重新分配或删除,请参阅

为什么可以将值重新分配给在const传递给.then()的函数中使用Promise.resolve()声明的变量,其中const传递const变量,但是无法将.then()变量与传递给Promise的函数重新分配给const构造函数,其中resolve()变量传递给Promise参数resolver构造函数"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)); 
}

const

修改,更新

为澄清查询的依据和动机,该问题试图确定何时可以使用与superconst声明相同的标识符,以及何时无法执行该程序。本质上,尝试创建一个标识符,在任何范围内抛出错误,尝试为标识符分配不同的值 - 无论是函数范围,块范围还是代码中的任何位置 - “Map”整数或者最接近当前可能的描述,具体取决于引擎。我们目前在最新的浏览器实施中最接近WeakMapclass或{{1}}吗?

2 个答案:

答案 0 :(得分:3)

您没有分配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()时,使用该名称时可以访问的ONLY变量是函数参数。该函数参数是另一个状态变量的副本,因为它作为参数传递给.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无法阻止使用本地范围内新声明的同名变量覆盖更高范围的变量。这不是语言功能。当解释器解析变量名时,它会将范围层次结构从本地搜索到全局,以便首先找到(并使用)本地定义。更高范围的定义在该范围内“覆盖”或“隐藏”。这就是他们如何设计变量名称解析以使用该语言。

这也有很多好处,因为有人突然声明你没有使用或甚至不知道的更高范围的变量将永远不会意外地破坏你的低范围声明。当你自己声明冲突并且你真的想要使用更高范围的命名时,那只是一个编码错误。如果您打算使用同名的更高范围的变量,则必须不声明冲突的名称。

答案 1 :(得分:1)

这里常量state变量没有变化。您正在更改传递给resolve函数的参数值。您可以在所有代码和输出都为console.log(state)后执行123来验证这一点。