异步作用域闭包

Posted llhweb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步作用域闭包相关的知识,希望对你有一定的参考价值。

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

答案:打印4次4

这道题涉及了异步、作用域、闭包

settimeout是异步执行,10ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是4,所以此时再去执行任务队列里的任务时,i全部是4了。对于打印4次是:

 每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了4次,就放了4次,当主线程执行完成后,才进入任务队列里面执行。
   (注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒。)
当我把var 变成let 时
for(let i=0;i<=3;i++){ setTimeout(function() {  console.log(i)  }, 10);}
打印出的是:0,1,2,3
当解决变量作用域,

因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

查了一下百度的一个答案:

setTimeout是一次执行函数,这里是10ms后执行,仅仅执行一次;for(var i=0;i<=3;i++),i的每次取值都是执行setTimeout这个函数,并没有执行setTimeout里面的function(即闭包函数),setTimeout里面的function是有setTimeout的定时触动的,也就是10ms后执行,也就是说i从0~3时,一共执行了4次的setTimeout()函数,此时的i的值是4,由于for语句的执行速度远小于1秒,所以,1秒后,由setTimeout()函数定时触动的闭包函数function()开始执行,alert(i);i的值已经是4了,所以相继打印4次i.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script type="text/javascript">
            function btn1 () { // 通过var定义的变量,作用域是整个封闭函数,是全域的 。通过let定义的变量,作用域是在块级或是子块中。
//                for (let i = 0; i < 5; i++) { // 0 1 2 3 4
//                  setTimeout(function() {
//                    console.log(i)
//                  }, 1000*i);
//                }
                for (let i = 0; i < 5; i++) {
                  setTimeout(function() { // 5 5 5 5 5 
                    console.log(i)
                  }, 1000*i);
                }
            }
            function btn2 () {
                for (var i = 0; i < 5; i++) { // 0 1 2 3 4 
                  (function(i) {
                    setTimeout(function() {
                      console.log(i);
                    }, i * 1000);
                  })(i);
                }
            }
            function btn3 () {
                for (var i = 0; i < 5; i++) { // 5
                  (function() {
                    setTimeout(function() {
                      console.log(i);
                    }, i * 1000);
                  })(i);
                }
            }
            function btn4 () {
                for (var i = 0; i < 5; i++) { // 0 1 2 3 4
                  setTimeout((function(i) {
                    console.log(i);
                  })(i), i * 1000);
                }
            }
            function btn5 () {
                setTimeout(function() { // 2 3 5 4 1
                  console.log(1)
                }, 0);
                new Promise(function executor(resolve) {
                  console.log(2);
                  for( var i=0 ; i<10000 ; i++ ) {
                    i == 9999 && resolve();
                  }
                  console.log(3);
                }).then(function() {
                  console.log(4);
                });
                console.log(5);
            }
        </script>
    </head>
    <body>
        <button onclick="btn1()">setTimeout1</button>
        <button onclick="btn2()">setTimeout2</button>
        <button onclick="btn3()">setTimeout3</button>
        <button onclick="btn4()">setTimeout4</button>
        <button onclick="btn5()">setTimeout5</button>
    </body>
</html>

 

以上是关于异步作用域闭包的主要内容,如果未能解决你的问题,请参考以下文章

前端知识体系:JavaScript基础-作用域和闭包-如何处理循环的异步操作

Javascript的那些硬骨头:作用域回调闭包异步……

JS闭包以及作用域初探

Javascript——闭包作用域链

如何快速的理解JavaScript闭包?

作用域链与闭包