美文网首页1000天日更计划
Day24:循环与闭包

Day24:循环与闭包

作者: 钱塘风华 | 来源:发表于2019-04-17 23:01 被阅读2次

【书名】:你不知道的JavaScript(上卷)

【作者】:Kyle Simpson

【本书总页码】:213

【已读页码】:65

for\ (var\ i=1; \ i<=5;\  i++)\ \left\{\\
\ \ \ \ \ setTimeout( function\ timer()\left\{\\
             console.log( i );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}, i*1000 );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

这段代码会输出什么呢?是分别输出数字 1~5,每秒一次,每次一个吗?

实际上,这段代码在运行时会以每秒一次的频率输出五次 6。

因为这个循环的终止条件是 i 不再 <=5。条件首次成立时 i 的值是6。因此,输出显示的是循环结束时 i 的最终值。

事实上,当定时器运行时即使每个迭代中执行的是setTimeout(.., 0),所有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个 6 出来。

我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个 i 的副本。但是根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分别定义的,但是它们都被封闭在一个共享的全局作用域中,因此实际上只有一个 i。

这样说的话,当然所有函数共享一个 i 的引用。循环结构让我们误以为背后还有更复杂的机制在起作用,但实际上没有。如果将延迟函数的回调重复定义五次,完全不使用循环,那它同这段代码是完全等价的。

如果让代码如我们预期地那样输出呢?

我们需要更多的闭包作用域,特别是在循环的过程中每个迭代都需要一个闭包作用域。

正好,IIFE 会通过声明并立即执行一个函数来创建作用域。

for\ (var\ i=1; \ i<=5;\  i++)\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
(function()\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\ \ \ \ \ setTimeout( function\ timer()\left\{\\
             console.log( i );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}, i*1000 );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\})();\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

事实上,这样还是不行。此时我们显然拥有更多的词法作用域了。的确每个延迟函数都会将 IIFE 在每次迭代中创建的作用域封闭起来。如果作用域是空的,那么仅仅将它们进行封闭是不够的。仔细看一下,我们的 IIFE 只是一个什么都没有的空作用域。它需要包含一点实质内容才能为我们所用。

它需要有自己的变量,用来在每个迭代中储存 i 的值:

for\ (var\ i=1; \ i<=5;\  i++)\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
(function()\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
var\ j=i;\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\ \ \ \ \ setTimeout( function\ timer()\left\{\\
             console.log(j);\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}, j*1000 );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\})();\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

OK,现在就可以了。

我们可以用传参的方式来优化这段代码:

for\ (var\ i=1; \ i<=5;\  i++)\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
(function(j)\ \left\{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\ \ \ \ \ setTimeout( function\ timer()\left\{\\
             console.log(j);\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}, j*1000 );\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\})(i);\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\
\right\}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \

在迭代内使用IIFE 会为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部,每个迭代中都会含有一个具有正确值的变量供我们访问。

相关文章

  • Day24:循环与闭包

    【书名】:你不知道的JavaScript(上卷) 【作者】:Kyle Simpson 【本书总页码】:213 【已...

  • Swift入门二(对象函数)

    函数 闭包 GCD 尾随闭包 闭包循环引用解决(OC) 闭包循环引用解决(swift推荐) 面向对象 命名空间: ...

  • swift-闭包

    闭包 闭包定义 闭包简化 - 尾随闭包 闭包参数 闭包返回值 闭包的循环引用

  • 循环与闭包

    概览 块级作用域与闭包的结合功能强大。 内容 思考: 分析:尽管循环中的函数是在各个迭代中分别定义,但是它们都被封...

  • 闭包与循环

    先来一个例子: 上面的例子中数组m中保存的函数返回值都为5。 why? 上述例子中的a是匿名函数,而执行匿名函数时...

  • iOS闭包循环引用精讲

    iOS闭包循环引用精讲 iOS闭包循环引用精讲

  • fou循环点击button 与闭包深入理解

    fou循环点击button 与闭包深入理解

  • 学习JS笔记(第七章-闭包,作用域)

    闭包的概念## 闭包实例## 数据传递更加灵活### 常见错误之循环闭包### 封装变量### 闭包小结## 作用...

  • Swift5.0 闭包

    本文目录: 闭包 尾随闭包 逃逸闭包 自动闭包 循环引用 闭包 全局函数:有名字,不捕获任何值; 嵌套函数:有名字...

  • Swift语法--12-3闭包的循环引用

    Swift语法--12-3闭包的循环引用 闭包循环引用产生条件 如果在HttpTool中有对闭包进行强引用,则会形...

网友评论

    本文标题:Day24:循环与闭包

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