关于 js 闭包和异步的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
ma199385
V2EX    程序员

关于 js 闭包和异步的问题

  •  1
     
  •   ma199385 2017-04-18 15:57:05 +08:00 2464 次点击
    这是一个创建于 3109 天前的主题,其中的信息可能已经有所发展或是发生改变。

    第一种情况

    for (var i = 0; i < 10; i++) { setTimeout(function(){ console.log('i-'+i); return function(){ console.log('i-'+i); } }(), 2000) } 

    执行结果为 i-1,i-2...i-9 。两秒后输出 10 次 i-10

    第二种情况 将代码改为如下

    for (var i = 0; i < 10; i++) { setTimeout(function(){ var s = i console.log('i-'+i); return function(){ console.log('s-'+s); } }(), 2000) } 

    执行结果为 i-1,i-2...i-9 。两秒后输出 s-1,s-2...s-9

    第三种情况

    for (var i = 0; i < 10; i++) { (function(){ console.log('i-'+i); return function(){ console.log('s-'+i); }() })() } 

    执行结果为i-1,s-1...i-9,s-9 这是什么原因呢

    8 条回复    2017-04-18 17:18:45 +08:00
    learnshare
        1
    learnshare  
       2017-04-18 16:01:30 +08:00
    闭包保存了“现场”,也就是当时的状态
    ma199385
        2
    ma199385  
    OP
       2017-04-18 16:04:33 +08:00
    @learnshare 您在看下我添加的第三种情况
    jklopsdfw
        3
    jklopsdfw  
       2017-04-18 16:31:11 +08:00 via Android
    @ma199385 第三种情况 return undefined ,然后两个立即执行函数,没毛病
    ma199385
        4
    ma199385  
    OP
       2017-04-18 16:34:19 +08:00
    @jklopsdfw 第一种情况和第二种情况能否说明闭包只关联上一个外层函数的变量
    kutata
        5
    kutata  
       2017-04-18 16:38:37 +08:00
    其实我觉得这应该是作用域的问题,面非闭包。
    第一种情况你把 var 改为 let 就输出就正常了。

    具体可以参考以下这篇文章,<块级作用域> 章节。
    http://lifemap.in/es2015-in-action/
    jklopsdfw
        6
    jklopsdfw  
       2017-04-18 16:41:26 +08:00 via Android
    @ma199385 第一种情况定时器调用的函数在两秒后只能找到两秒后外层的 i ,第二种情况定时器调用的函数两秒后找到两秒前赋值的 s ,第三种情况没有定时器,啥时候调用就找啥时候的 i
    xss
        7
    xss  
       2017-04-18 16:52:27 +08:00
    你的 setTimeout 里面的回调函数, 存在于特定的上下文中.
    顺着原型链网上找:
    1. 首先 i-1,i-2...i-9 是第一个 console.log 输出的.然后 2 秒之后返回了函数,此时 for 循环已经执行完毕, i 的值在原型连上是 10, 所以再输出 10 次 10.

    2. 第一次的输出同 1, 不同的是, 第二次输出的是 s 的值, 而每次原型链上 s 的值是 i 的副本(值传递), 所以第二次会输出 s-(保存的 i 值), s-(保存的 i 值). 但是注意, 实际上保存的 i 值的顺序并不一定是递减或递增的关系, 在极端情况下可能是乱序的. 这个和定时器的精度有关.

    3. 函数调用栈问题, 最外侧匿名函数首先被调用, 然后内部的匿名函数再获得调用机会. 每次 for 循环都是如此, 先调用外部的函数, 输出 i-1, 然后内部匿名函数获得调用, 输出 s-1, 其余情况类推.
    ma199385
        8
    ma199385  
    OP
       2017-04-18 17:18:45 +08:00
    @kutata
    @jklopsdfw
    @xss 万分感谢
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3003 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 13:04 PVG 21:04 LAX 06:04 JFK 09:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86