美文网首页JavaScript 进阶营程序员
探讨循环与回调函数问题

探讨循环与回调函数问题

作者: 老邵 | 来源:发表于2018-04-02 20:52 被阅读61次

循环与回调函数的问题,也就是作用域与闭包的问题。个中原因是 JavaScript 的两个特性:

  1. JavaScript 不支持块作用域
  2. 只要使用了回调函数就是在使用闭包

第一个特性就是字面的意思,第二个特性是由闭包的特性引申出来的。

从实际代码的角度来讲,闭包是在定义时所在作用域以外执行的函数。而 js 引擎在执行 js 代码,就会将回调函数丢给事件触发线程。当回调函数执行时,回调函数是在定义时所在作用域以外,所以说只要使用了回调函数就是在使用闭包。

弄清楚了概念,来看一下循环与回调函数的问题,以下方代码为例:

var btns = document.querySelectorAll("button");
for(var i = 0; i  <  btns.length;i++){//假设 btn.length 为 6
btns[i].onclick = function() {
              console.log(i);
      }
}

这段代码中,打印 i 所在的匿名函数是一个回调函数。当按钮点击时该函数就会触发,打印循环时的 i。然而结果出人意料,每次点击时输出的数字都是 6,为什么会这样呢?

首先是因为 js 没有块作用域,for 循环多次迭代中只是声明了一个 i,所以最后 i 只有一个值,也就是循环结束时的值。

其次是因为回调函数是闭包,所以在作用域外引用作用域中的 i,这个 i 只有一个最终值。

这个例子也可以换一个角度来想。如果 js 支持块作用域,那么上方代码中每个按钮的回调都声明在不同的块作用域中。只要每次迭代保存一下 i 的值,如使用 var j = i,那么每次打印 j,就可以打印 i 的不同值了。

根据上方的原因分析,我们可以得出解决方案——使 i 的值声明或保存在不同的作用域中。具体方法多种多样,下面列举两个解决方法:

  1. var btns = document.querySelectorAll("button");
     for(let i = 0; i  <  btns.length;i++){//假设 btn.length 为 6
     btns[i].onclick = function() {
                 console.log(i);
           }
     }
    

let 是 ES6 的关键字,用来声明一个块级作用域的本地变量,并使变量每次迭代时声明一次。

  1. var btns = document.querySelectorAll("button");
     for(var i = 0; i  <  btns.length;i++){//假设 btn.length 为 6
         (function(){
            var j = i;
            btns[i].onclick = function() {
                        console.log(j);
                }
           })();
     }   
    

(function(){})()是一个立即执行函数,每次迭代中都有一个不同的函数作用域,在其中保存 i 的当前值并使用。

James Harris 2017-01-20 08-48-05 .jpg

相关文章

  • 探讨循环与回调函数问题

    循环与回调函数的问题,也就是作用域与闭包的问题。个中原因是 JavaScript 的两个特性: JavaScrip...

  • JavaScript回调函数探讨

    一、背景 在JavaScript的学习中,回调函数一直是比较令人头疼的东西,回调也是编写和处理 JavaScrip...

  • array_map函数

    传入该函数的数组会循环遍历,每次循环都会执行回调方法,循环的时候只会取出value值,不会对key进行操作,在回调...

  • 前端入门11 -- JavaScript之Promise

    回调函数 回调函数分为两种类型,分别为同步回调与异步回调; 同步回调:会立即执行,完全执行完了才结束,不会放入回调...

  • 理解回调函数

    最近经常看到“回调函数”这个概念,但不是很理解。为了弄明白回调函数,提出了以下三个问题:1.什么是回调函数 回调函...

  • JavaScript中的tasks和microtasks

    之前这篇文章介绍回调函数的时候提到了函数调用栈和任务队列的概念,当时并没有深入探讨任务队列这个概念,只提到回调函数...

  • 异步的发展

    回调函数存在两个问题1、不能try catch执行异步代码,结果放在回调函数里面回调函数再执行,这是两个不同的过程...

  • JavaScript函数_08回调函数

    回调函数 回调函数(回调),当我们把某个函数作为参数传递给另一个函数的时候,这个函数就是回调函数 回调函数的基本写...

  • nodejs--day4笔记

    1. 同步与异步API 回调函数 通过回调函数返回异步API的值 代码执行顺序 2. promise 解决回调...

  • 如何正确的使用Promise

    promise用法 对比传统回调函数与Pormise的写法 传统回调函数 Promise的写法 Promise要比...

网友评论

    本文标题:探讨循环与回调函数问题

    本文链接:https://www.haomeiwen.com/subject/ezgncftx.html