for循环中的作用域问题

image.png

浏览器内部如何描述作用域,这个for循环是不是相当于产生了 btns.length个作用域,在这些作用域里有一个变量i,有一个具体值,分别是1,2,3,4,5等等,这个作用域是在栈中的一个具体空间吗?

补充一下完整代码
image.png

这段代码for循环如果用var,点击直接报错
如果使用let,是一段正常代码,

阅读 3.3k
4 个回答
for (let i = 0; i < 10; i++) {
    let i;
    console.log(i);
}

来看这一段代码,发现了什么?第二个 let i 居然没报错,那说明 for 作用域和 for 循环体作用域不同。因为如果是同一个作用域是不能对同一个变量声明多次的,比如下面这个就会报错

let i;
let i;  // SyntaxError: Identifier 'i' has already been declared

尝试下面这段代码也可以发现两个 i 是不同的

for (let i = 0; i < 10; console.log("i", i++)) {
    let i;
    console.log(i);
}

然后是一个比较神奇的事情

for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 500);
}

这段代码可以打印出 0~4,但是

let i = 0;
for (; i < 5; i++) {
    setTimeout(() => console.log(i), 500);
}

这段代码打印出来全是 5

这说明 for 作用域和 for 循环体作用域并不只是两层作用域那么简单。从效果上来看,for 作用域中的变量在其循环体作用域中会有一个副本,所以延迟打印才不会总是打印出最后一个值。注意:我说的是从效果上看。本质是怎么回事,不敢妄加揣测,最好还是去 ECMA-262 中找找答案。

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

变量i绑定到了for循环每次迭代的块作用域中,在上一个循环结束的时候,进行重新赋值

它的执行过程像这样:

 {
   let j;
   for (j=0; j<10; j++) {
     let i = j; // 每个迭代重新绑定! 
     console.log( i ); 
   } 
 }

补充:

如果你想使用var,可以这样:

 for (var i = 0; i < btns.length; i++) {
    btns[i].onclick = (function (j) {
      return function () {
        console.log(j);
        btns[j].style.backgroundColor = 'red';
      };
    })(i);
  }

在IIFE里传一个参数进去,这样,每次循环都创建一个新的作用域,并把它封闭在闭包里,每次循环也都会有一个正常都值了

新手上路,请多包涵

首先回答问题:该i确实是在一个作用域中,且该作用域因为引用的关系而不会被删掉,假如说的栈是js的存储类型的话,那这个栈是指存的i,而如果栈指的是作用域链的话,那前面的回答就足够了。
接着说下这个代码的关键点,每次console.log会输出btns.length的值。

还是深刻理解JS的花括号吧。

{
    const a = 'Hi';
}
console.log(a);

以上代码运行结果是打印'Hi'吗?当然不是,a是undefined。
花括号代表了作用域是相当顶级的规则,因此for(...){}中,括号中的内容属于外部域,花括号内是内部域。且同样遵循内部域可以直接调用外部域中已声明的变量的规则。

var现在已经不推荐使用了,还是与时俱进吧。而且建议初学者应该学习“应该怎样用”而不是“不报错就好”。从你的代码看是想点击哪个哪个变红,而且是abcd四个button的话,难道是选择题的答案处理?那怎么单选?选中了怎么取消?这些都是要处理的,可不是现在这几行能搞定的。

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题