javascript - `var` 中的 `if` 是否会影响 if 是否被评估?

标签 javascript if-statement scope global

这是与 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,它会更改变量的状态 达到代码更改之前

在这个变体中,除了在 if 的行中添加 var 之外没有任何变化,变量切换为 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);

})();

控制台显示变量现在在 if 之前为 undefined,并由现在评估的 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 执行仅受未评估代码影响的示例?)

最佳答案

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

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


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

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

查看基准测试:包含 eval 的代码片段运行速度明显低于不包含的代码片段:http://jsperf.com/eval-hurts-performance .

关于javascript - `var` 中的 `if` 是否会影响 if 是否被评估?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25061219/

相关文章:

javascript - 迭代父元素

javascript - 修复放大和缩小编码

c++ - 为什么这段代码会跳过设置字符串变量的 if 语句?

javascript - 无法读取未定义的属性

javascript - 无法加载使用命名定义调用的模块

MySQL - IF 查询 STR_TO_DATE

php echo 如果两个条件都为真

c++ - 在 C++ 中,如果我引用一个带有释放析构函数 ~MyClass 的对象,超出范围的引用会调用析构函数吗?

Javascript 作用域、内联函数和异步操作

c++ - 什么时候在 C++ 中调用复制构造函数? - 函数返回