局部变量和 for 循环语句

2017-05-12  本文已影响69人  唯泥Bernie

这篇只是简单的做下记录吧,作用域在 js 中真是个麻烦的东西,实在有太多的 case by case 的情况,无法用一个原理推出其他的,先来代码:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>
<script>
  var lis = document.querySelectorAll( 'li' );
  // 用 var 声明循环变量
  for( var i = 0; i < lis.length; i++ ) {
    lis[ i ].onclick = function() {
      alert( i ); // 点击任何一个 li 都是 alert 3
    }
  }
  // 用 let 声明循环变量
  for( let j = 0; j < lis.length; j++ ) {
    lis[ j ].onclick = function() {
      alert( j ); // 点击 li 分别显示 0,1,2
    }
  }
</script>

用 var 声明的变量不是块级的,所以整个循环过程中 i 变量只有一个,当你注册完 onclick 之后再点击,所有函数引用的是同一个 i,所以 alert 出来的是 i 的最终值 3。而如果用 let 声明为什么会产生不同的效果?

从常识推断:j 虽然是块级作用域变量,但是仅仅能说明在 for 循环外面拿不到 j。并且 for 循环第一个分号前的代码只会执行一次,即使如果每次循环 j 都是生成一个新的局部变量,那么 j++ 为什么能保持 j 数字的递增呢?

好吧,只能再去撸下规范。原来规范里面针对这种情况是这么规定的(我依然只是说明下大致的步骤):

  1. 每次循环都会新建一个块级作用域;
  2. 相应的 for 循环第一个分号前所有用 let 声明的局部变量都会重新新建。
  3. 然后把上一次循环后变量的值赋值给这次循环生成的新局部变量(当然是找同名的啦)。

所以就能解释上面代码用 let 声明的情况了,再写一个示例代码来验证下规范的逻辑:

for ( let a = 0, b = 10; a < 5; a++, b++ ) {
  console.log( 'a:' + a + ' | b:' + b );
}
/*
结果:
a:0 | b:10
a:1 | b:11
a:2 | b:12
a:3 | b:13
a:4 | b:14
*/

for ( let c = 0, d = 10; c < 5; ) {
  console.log( 'c:' + c + ' | d:' + d );
  c++;
  d++;
}
/*
结果:
c:0 | d:10
c:1 | d:11
c:2 | d:12
c:3 | d:13
c:4 | d:14
*/
上一篇下一篇

猜你喜欢

热点阅读