var 的迷惑行为(作用域提升 preprocess, 现在叫 BoundNames)

var的作用域提升

我们先来看下面的代码

for(; i < 10; i++) {
  let i = 0;
  console.log(i)
}
// Uncaught ReferenceError: i is not defined at <anonymous>:1:9

这意味着let 并不会有作用域的提升

接下来我们看下面的代码

var i = 0
for(;i < 10; i++) {
  let i = 0;
  console.log(i);
}
// 输出了 10 个 0

我们来分析一下这段代码,我们看到,开始的用 var 定义的 i,在循环体里面随着 i <10 做了十次自增。然后在子作用域里面又存在着一个自作用于里面的 i,循环了十次,输出了 10 次 let i = 0

紧接着,我们再看看下面的这段代码

for(; i < 10; i++) {
  let i = 0;
  console.log(i);
}
// Uncaught ReferenceError: i is not defined at <anonymous>:1:9

然后对比这个

for(; i < 10; i++) {
  var i = 0;
  console.log(i);
}
// undefined

再看看这个

for(let i = 0; i < 10; i++) {
  let i = 0;
  console.log(i);
}
// 输出了 10 个 0,只是说在这里面就拿不到 i 了

// 以上这个我们可以理解为 父作用域和子作用域,类似于:
{
  let i =0;
  {
    let i = 1;
    console.log(i);
 	)
  console.log(i);
}
// 1 0

var 是有迷惑行为的(var 预处理机制)

for(i = 0; i < 10; i++) {
  var i;
  console.log(i);
}

// 等同于
var i;
for(i = 0; i < 10; i++) {
  console.log(i);
}

//等同于
for(i = 0; i < 10; i++) {
  console.log(i);
  var i;
}
//甚至等同于
for(i = 0; i < 10; i++) {
  console.log(i);
}
var i;
// Weird code
var x = 0
function foo() {
  var o = { x: 1 }
  x = 2
  // var x = 2
  // 'with' declared a seperate block
  with (o) {
    var x = 3
  }
  console.log(x)
}
foo()
console.log(x)

也就是说,不管 var 加在函数里面的什么地方,var 自动会变量提升到函数的最开始,对整个函数进行赋值操作,这是很迷惑的一个东西
所以,以后用 var,一定要在文件、函数的最开头声明

Brendan Eich:javascript-[with,var]这俩就是两个设计错误

winter:

  1. 如果非要用 var ,不建议大家写在任何的语句的子结构里面。有 var,我们一定要写在 function 的范围内,并且写在最前面,至少要写在第一次这个变量名出现的地方

    function foo() {
      var o = {x: 1};
      x = 2;
      if(false) {
        // 这句 var x = 1,也改变了 x = 2 的行为
        var x = 1;
      }
      console.log(x);
      
      return
      // 这个 x = 3,照样改变了上面 x = 2 的行为
      var x =3
    }
    foo()
    console.log(x);
    
  2. 不要在任何的 block 里面写 var,其实在有的javascript编程规范里面建议完全舍弃 var,就用 let 还有 const,痛苦一点但是 resonable

原文地址:https://www.cnblogs.com/ssaylo/p/12984387.html