为什么块分配值会更改全局变量?

时间:2020-04-13 15:18:51

标签: javascript

var a = 0;
if (true) {
  console.log(a)
  a = 1;

  function a() {}
  a = 21
  console.log(a)
}
console.log(a)

在我看来,由于函数声明的提升,a = 1a = 21会更改局部函数变量,因此in块中将输出21,而outside为0,但真正的结果是在output 1外。

使用chrome调试,结果是这样

function a() {}上运行时,它将更改局部变量和全局变量。太奇怪了? 谁能给我一些解释?

4 个答案:

答案 0 :(得分:12)

观察到的行为是非严格模式所特有的,并且Firefox执行相同的操作。

之所以采用这种方式,是因为它遵循规范Annex B 3.3中所述的Web兼容性语义。

细节非常复杂,但这是此部分引擎的实现者的实现:

当块中存在内部函数a时,处于草率模式,并且当 Web兼容性语义适用(在 规范),然后:

  1. 内部函数a通过类似let的块作用域(“ (let) a”)被提升
  2. 同时,在包含以下内容的范围中创建了一个变量,其名称也为a,但语义为var(即函数作用域) 块(“ (var) a”)
  3. 当到达声明内部函数的行时,(let) a的当前值将被复制到(var) a(!!)
  4. 从块内部对名称a的后续引用将引用(let) a

因此,对于以下情况:

1:  var a = 0
2:  if(true) {
3:    a = 1
4:    function a() {}
5:    a = 2
6:  }
7:  console.log(a)

...这是发生了什么

第1行:在外部作用域的变量环境中添加了(var) a,并为其分配了0

第2行:创建了一个if块,将(let) a(即function a() {})提升到块的顶部,使(var) a阴影< / p>

第3行: 1被分配给(let) a(注意,不是(var) a

第4行:(let) a的值被复制到(var) a中,因此(var) a变为1

第5行: 2被分配给(let) a(注意,不是(var) a

第7行: (var) a被打印到控制台(因此1被打印)

Web兼容性语义是一些行为的集合,这些行为试图对后备语义进行编码,以使现代浏览器能够尽可能多地与Web上的旧代码保持向后兼容性。这意味着它将对规范外部实施的行为进行编码,并由不同的供应商独立进行。在非严格模式下,由于浏览器供应商“走自己的路”的历史,几乎可以预期会有奇怪的行为。

但是,请注意,规范中定义的行为可能是错误沟通的结果。 Twitter上的Allen Wirfs-Brock said

无论如何,根据我想像的任何合理解释,最后报告的a == 1的结果都不正确。

... and

应该为function a(){}!因为在块内,对a的所有显式引用都是对块级绑定的。只有隐式的B.3.3分配应该转到外部的a

最后的注释:Safari给出了完全不同的结果({0由第一个console.log打印,21由后一个console.log打印)。据我了解,这是因为Safari尚未对Web兼容性语义(example)进行编码。

故事的道德?使用严格模式。

Moredetailsherehere

答案 1 :(得分:0)

这也是“有趣的”。似乎a = 21a分配给了全局变量,并且函数引用不可访问。

var a = 0;
if (true) {
  function a() {}
  console.log(typeof a, a) // number 0
  a = 21;
}
console.log(typeof a, a) // number 21

答案 2 :(得分:-1)

a = 1;重新分配给原始变量,使其值为1function a() {}仅在if条件下屏蔽a并“接管” a。详细了解shadowing and masking

答案 3 :(得分:-2)

嗨。 让我们以这种方式看一下,当您声明一个名为'a = 1'的变量(声明的变量是全局变量)时,会将一个内存房子分配给 变量 具有以下值:1
在声明函数之后: function a() {} 不再有'a'变量类型的存储空间,并且a是一个函数。 但是,'a'的存储空间没有清除,仍然可用,就像一个被调用一次并返回最后一个赋值的函数一样! 因此,当您编写以下代码时:

  a = 1;
  function a() {}

它就像:

function a(){
return 1;
}
console.log(a());

这个问题就像是由于不完整的性质(我的意思是记忆库类型)改变一样。