【问题标题】:Presence of `var` within an `if` influences whether the if is evaluated?`if` 中存在 `var` 会影响 if 是否被评估?
【发布时间】:2014-09-23 12:50:25
【问题描述】:

这是我不太了解的 Javascript 作用域和全局变量与局部变量的一些特定微妙之处 - 并且可能导致 if 条件中的代码出现令人惊讶的情况,从而影响 if 条件是否为评估:代码受到尚未“发生”的代码的影响。

我已将其缩减为 JSBIN DEMO 比较两个几乎相同的代码块。


首先,一切都按预期进行。我们定义了一个全局变量,然后在一个范围内,我们检查它是否被定义,看看它是,然后继续:

someVar = function(){}; // or, window.someVar =...

(function(){

console.log("before", someVar, typeof someVar);
if(typeof someVar == 'undefined'){
  someVar = true;
}
console.log("after", someVar, typeof someVar);

})();

控制台显示变量是一个函数,并且 if 被跳过,正如预期的那样。

但是,如果我们将if 中的行更改为使用var,它会更改变量之前 中更改的状态代码已到达

在这个变体中,除了将var 添加到if 内的行之外,没有任何变化,变量之前两行切换到undefined,现在评估if

someVar = function(){}; // or, window.someVar =...

(function(){

console.log("before", someVar, typeof someVar);
if(typeof someVar == 'undefined'){
  var someVar = true; // <<<<< the only change is adding var here
}
console.log("after", someVar, typeof someVar);

})();

控制台显示变量现在是 undefinedif 之前,并由现在正在评估的 if 切换。

编辑:即使var 声明永远不会发生,也会发生同样的事情:

neverVar = function(){}; // or, window.neverVar ...

(function(){

console.log("never-before", neverVar, typeof neverVar);
if(false){ // never do this
  var neverVar = "changed";
}
console.log("never-after", neverVar, typeof neverVar);

})();

我认为 JS 代码不可能在到达之前影响代码的执行 - 但显然 var 稍后在代码中的存在以某种方式阻止了整个范围的全局查看。

从 jsbin 的警告来看,它是否被认为超出范围取决于范围内是否存在 var 语句,即使该 var 语句尚未被评估或预计不会被评估评估。

谁能解释一下?


(出于好奇,还有其他的 Javascript 执行示例会受到未评估代码的影响吗?)

【问题讨论】:

  • 除了给出的答案,别忘了Javascript默认作用域不是块作用域,是函数作用域。

标签: javascript if-statement scope global


【解决方案1】:

它被称为variable hoisting,在实际执行其余代码之前处理变量和函数声明。

每当在非全局范围内遇到var 时,都会在该范围内的undefined 处声明和初始化一个新变量。由于if 没有引入新的(块)作用域,var 内部的ifvar 从父作用域中隐藏起来。


奖励:关于您的附带问题,是否还有其他 JavaScript 执行示例受无法访问的代码影响:是的,但仅在性能方面。现代 JavaScript 解释器非常复杂,并试图尽可能地优化解释代码。有some constructs 会导致性能下降,即使它位于无法访问的代码块中。例如:

for (var i=0; i<100000000; ++i) ; // Busy loop
if (false) {
   eval(); // BOOM - Killed optimizations.
}

查看基准:包含 eval 的 sn-p 运行速度明显慢于不包含 http://jsperf.com/eval-hurts-performance 的 sn-p。

【讨论】:

  • 太棒了,谢谢 - 我已经困惑了将近 1 1/2 小时,而您在 90 秒内回答了!快速查询:您能在这种情况下澄清“遇到”吗?根据我的幼稚理解,if 中的代码不会被评估 - 但大概在实际评估代码之前发生了某种对整个范围的扫描?
  • @user568458 “遇到”,如“出现在函数中”。阅读我链接的文章以获得更全面的解释。
  • @user568458 我刚刚注意到你的附带问题,并在我的答案末尾附上了一个小评论,仅供参考;)
  • :D 谢谢!那篇文章中的这一行确实很有帮助:“函数声明和变量声明总是被 JavaScript 解释器以不可见的方式移动(“提升”)到其包含范围的顶部”。大概意思是function(){ ...some code... var someVar = 10; } 被视为与function(){ var someVar; ...some code... someVar = 10; } 相同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
  • 2020-08-15
  • 2020-09-30
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多