关于4-5编程练习的一些理解,希望老师解答,谢谢

来源:4-5 编程练习

夜魇丶

2019-08-14 23:10:53

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8">

  <title>变量、作用域</title>

</head>

<body>

  <button>1</button>

  <button>2</button>

  <button>3</button>

  <script type="text/javascript">

  // 原代码

  // var btns = document.getElementsByTagName('button'); 

     // for (var i = 0; i < 3; i++) {

      // btns[i].onclick = function () {

      // console.log(i);

      // alert(i + 1);

    // };

   // }

  //在此处修改代码

  var btns = document.getElementsByTagName('button');

  for (var i = 0; i < 3; i++) {

    demo(i);

  }

  function demo(i){

    btns[i].onclick = function(){

      alert(i + 1);

      console.log(i);

    }

  }

  </script>

</body>

</html>


看着问答区的回答想了一个小时还是不算太明白。

1. 在执行循环之前i就等于3了,那就是不是意味着浏览器刚加载完,这个循环就已经执行完了。

2. 而在原题中,点击第一个按钮的时候,i已经为3了,但是我点第一个按钮时应该执行btn[0].onclick,我执行btn[0]的话说明此时此刻i=0才对,alert为什么会按3来执行?我的理解是for循环执行之后,生成了三个btn单击事件,分别为btn[0]、btn[1]、btn[2]。但是只是生成了这三个事件,因为没有点击所以没被触发,而当点击的时候浏览器已经把循环执行完了,i已经赋值为3,所以产生了这种情况。

3. 我看老师解答说原代码里面没有作用域保存每次循环的i值。那第二个代码中,是demo中自动生成一个var i来保存i值么,为什么第一个代码就不能在点击的时候自动生成一个作用域保存i值?

我可不可以理解为:浏览器加载完了,已经执行完for循环了。在浏览器中产生了三组函数,demo(0)、demo(1)、demo(2);这三个函数已经被分别绑在三个按钮上了。而在demo(0)里面是btn[0],这个地方是局部的i值为0,demo(1)里面是btn[1],i值为1,demo(2)里面是btn(2),i值为2;而在全局中,i值为3;

4. 作用域链是内层优先级高,从内向外搜索i值。在demo里已经生成了一个局部的i值,只是没有被显示出来。三个demo有三个不同的局部i值。而在第一个代码中,事件已经生成,这个循环里的只有一个全局的i值,就是3。for循环每循环一次产生一个i值,但是这个i值都被后续的i值覆盖了。我可不可以这样理解?

5. 我看到有把var改成let,然后代码完美执行的。var是定义全局变量,let是局部。这样做的作用是什么?难道是let在循环的时候,在三个btn事件中,产生了三个局部的i。而var之所以不行,就因为是全局地,在循环的时候被覆盖掉了?

6. 在第二个代码中,每循环都会产生一个新的作用域,保留i值,在第一个代码中,每次循环没有作用域产生,i值被覆盖,是这么理解么?那新作用域指的是demo(0)、demo(1)、demo(2)吗?


……一团乱,不知道具体是哪个地方理解有问题,我知道作用域链是干什么的、怎么运作的。可是遇到这道题连作用域是什么我都快搞不清楚了。说的有点乱(非常沮丧这个编程题现在已经花了一个半小时了,还是没弄明白。理解能力有限)也可能是for循环的运作我也没弄明白。总之辛苦老师解答了。对不住,辛苦了。


写回答

1回答

好帮手慕慕子

2019-08-15

同学你好

  1. 这里理解有一点误差哦,在for循环之后i的值才等于3,

    http://img.mukewang.com/climg/5d54ee850001d67c04320224.jpg

    http://img.mukewang.com/climg/5d54ee9200014e6b02490079.jpg

  2. 你这样理解是可以的, 循环的时候,只给按钮绑定了事件, 并没有被触发,for循环已经执行完毕i的值为3.  所以当我们点击按钮的时候,弹出的i是3。

  3. 函数每调用一次,就会生成一个单独的作用域, 将传入的i值保存在该函数作用域中。点击按钮的时候,在对应的函数作用域找到对一个i值

    因为,第一段代码, for循环是在全局作用域中, for循环执行完之后i的值为3. 点击按钮,沿着作用域链向上查找到全局作用域中i值3

    同学这样理解也是可以的

  4. 可以这样理解, 很对哦

  5. let是ES6新增的一个声明变量的关键字, 可以理解为在循环的时候, let声明的变量可以产生了一个局部作用域保存每次循环的值, 点击按钮时候,向上查找到let的局部作用域保存的i值。

    使用var声明的是全局的,循环的时候会被覆盖掉, 这样理解是可以的

    关于let,后面ES6章节会有详细的讲解, 目前同学知道有这种方式就可以了

  6. 理解是对的, 新作用域是指的函数的作用域, 也就是demo(0)等。 老师也画了一个图帮助同学从作用域链方面理解

    http://img.mukewang.com/climg/5d54f6e100010e4505730486.jpg

综上所述, 其实同学理解的是可以的,不用太纠结, 目前, 就简单的认为, 直接在for循环中给按钮绑定点击事件,点击事件是在点击按钮的时候才出发, 此时for循环早就执行完了, 所以弹出i的值为3.  修改为第二种方式, 使用调用函数的时候会生成一个独立的作用域, 可以保存for循环传入的i值, 当点击按钮的时候可以向上查找到函数作用域的i的值

如果帮助到了你,欢迎采纳!

祝学习愉快~~

1

0 学习 · 14456 问题

查看课程