美文网首页
JS let/for循环问题/作用域/上下文环境随笔

JS let/for循环问题/作用域/上下文环境随笔

作者: 377b79b94683 | 来源:发表于2017-07-17 21:25 被阅读280次
    遇到这么个题,结果因吹丝挺 试了一下这样结果更因吹丝挺了 ???什么鬼???

    setTimeout会把回调放到代码执行完毕后,再做处理,so


    显然setTimeout里的1是在程序执行完毕后才执行的

    所以就不难理解为什么第一张图会打印5个5了,因为不管setTimeout再快,也得在程序执行完毕后打印,而程序执行完毕时,for已经循环了5次了.....

    所以呢,还有个问题,在setTimeout把方法放到任务队列之后,会不会保留上下文环境?答案是肯定的。

    • 无论函数是在哪里调用,也无论函数是如何调用的,其确定的词法作用域永远都是在函数被声明的时候确定下来的。
    • 当定义一个函数时,它实际上保存一个作用域链。
    • 当调用这个函数时,它创建一个新的对象来储存它的参数或局部变量,并将这个对象添加保存至那个作用域链上,同时创建一个新的更长的表示函数调用作用域的“链”。
    • 对于嵌套函数来说,情况又有所变化:每次调用外部函数的时候,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用域链都是不同的。内部函数在每次定义的时候都要微妙的差别---在每次调用外部函数时,内部函数的代码都是相同的,而且关联这段代码的作用域链也不相同。
    好烦啊终于搞定了,这样就可以证明在使用let的情况下每次循环中声明的回调的作用域链被固定下来啦
    • 当使用var声明变量的时候,没有块级作用域,因此每次循环中声明的setTimeout的回调,是去更高一级的作用域中寻找变量i。
    • 当使用let声明变量的时候,有独立的块级作用域,因此声明setTimeout回调的时候,是在本次循环的块级作用域{}中寻找变量i。

    如上图,在定义循环时,同时定义n,在回调中修改n的值以修改回调执行结果,如果是var声明的,则第一次执行的结果会对后面两次造成影响,而使用let声明n,则三次循环完全互不干扰,可知在使用let定义n时,循环定义的三个回调函数的作用域链被各自分隔开。var声明的i和let声明的i在作用域链上的位置不同。

    最后总结一下:

    不管是var也好,let也好,循环定义的若干个setTimeout的回调都属于同一个上级作用域,但是回调之间是独立存在的,不会相互影响;不一样的是:var和let在各自作用域链上的位置不同,var没有块级作用域,所以var所在作用域属于上级作用域;let有块级作用域,所以在for循环的时候,i的作用域被限制在了{}代码块之间,分别在三个{}中定义setTimeout回调的时候,i在作用域链中的位置分属三个回调所在的块级作用域,互不干扰。

    var循环 let循环

    PS:只有在调用到块级作用域中变量的时候,才会将块级作用域添加到作用域链中
    PS2:三个回调并非在一个块级作用域下被依次声明,而是将块级作用域循环了三次,每次分别声明了自己作用域下的方法。
    PS3:知道为什么就知道怎么影响这个块级作用域啦,引用传递可破,可知作用域变量遵循普通变量传递原则。


    如何影响块级作用域

    PS4:作用域链的非自己部分在函数对象被建立(函数声明、函数表达式)的时候建立,而不需要等到执行,这部分作用域链是静态的;当函数执行时,建立一个自己当次执行的作用域,然后把这个作用域与前面的作用域链关联起来

    相关文章

      网友评论

          本文标题:JS let/for循环问题/作用域/上下文环境随笔

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