stm32怎么调用for循环内部的变量_循环中的异步amp;amp;循环中的闭包
在這之前先要了解一下
for循環中let 和var的區別
var 是函數級作用域或者全局作用域,let是塊級作用域 看一個例子
????function?foo()?{
??????for?(var?index =?0; index < array.length; index++) {
????????//..循環中的邏輯代碼
??????}
??????console.log(index);//=>5
????}
????foo()
???console.log(index)//Uncaught ReferenceError: index is not defined
foo函數下的index輸出5,全局下的index不存在
現在我們把var 換為let
????function?foo()?{
??????for?(let?index =?0; index < array.length; index++) {
????????//..循環中的邏輯代碼
??????}
??????console.log(index)//Uncaught ReferenceError: index is not defined
????}
????foo()
報錯了,index不在foo函數作用域下,當然肯定也不會再全局下
因為var和let的這個區別(當然var和let的區別不止于此)所以導致了下面的這個問題
關于var
????const?array = [1,?2,?3,?4,?5]
????function?foo()?{
??????for?(var?index =?0; index < array.length; index++) {
????????setTimeout(()?=>?{
??????????console.log(index);
????????},?1000);
??????}
????}
????foo()
看下輸出
關于let的
????const?array = [1,?2,?3,?4,?5]
????function?foo()?{
??????for?(let?index =?0; index < array.length; index++) {
????????setTimeout(()?=>?{
??????????console.log(index);
????????},?1000);
??????}
????}
????foo()
看下輸出
因為var和let 在作用域上的差別,所以到這了上面的問題
使用var 定義變量的時候,作用域是在foo函數下,在for循環外部,在整個循環中是全局的,每一次的循環實際上是為index賦值,循環一次賦值一次,5次循環完成,index最后的結果賦值就為5;就是被最終賦值的index,就是5;
let的作用局的塊級作用局,index的作用域在for循環內部,即每次循環的index的作用域就是本次循環,下一次循環重新定義變量index;所以index每次循環的輸出都不同
這里還有另外一個問題,setTimeout,這是一個異步,這就是我們今天要討論的
循環中的異步
setTimeout(func,time)函數運行機制
setTimeout(func,time)是在time(毫秒單位)時間后執行func函數。瀏覽器引擎按順序執行程序,遇到setTimeout會將func函數放到執行隊列中,等到主程序執行完畢之后,才開始從執行隊列(隊列中可能有多個待執行的func函數)中按照time延時時間的先后順序取出來func并執行。即使time=0,也會等主程序運行完之后,才會執行。
一個需求,一個數組array[1,2,3,4,5],循環打印,間隔1秒
上面的let是循環打印了12345,但是不是間隔1s打印的,是在foo函數執行1s后,同時打印的
方式一, 放棄for循環,使用setInterval
????function?foo(){
??????let?index =?0;
??????const?array = [1,?2,?3,?4,?5]
??????const?t = setInterval(()=>{
????????if?(index < array.length) {
??????????console.log(array[index]);
????????}
????????index++;
??????},?1000);
??????if?(index >= array.length) {
????????clearInterval(t);
??????}
????}
????foo()
我們上面說到,當for循環遇到了var,變量index的作用域在foo函數下,循環一次賦值一次,5次循環完成,index最后的結果賦值就為5;就是被最終賦值的index,就是5;
方式二,引入全局變量
代碼執行順序是,先同步執行for循環,再執行異步隊列,在for循環執行完畢后,異步隊列開始執行之前,index經過for循環的處理,變成了5。
所以我們引入一個全局變量j,使j在for循環執行完畢后,異步隊列開始執行之前,依然是0,在異步執行時進行累加
????var?j =?0;
????for?(var?index =?0; index < array.length; index++) {
??????setTimeout(()?=>?{
????????console.log(j);
????????j++;
??????},?1000?* index)
????}
方式三, for循環配合setTimeout(常規思路,不贅述,面試必備技能)
????const?array = [1,?2,?3,?4,?5]
????function?foo()?{
??????for?(let?index =?0; index < array.length; index++) {
????????setTimeout(()?=>?{
??????????console.log(index);
????????},?1000*index);
??????}
????}
????foo()
方式四,通過閉包實現
開始討論方式四之前我推薦先閱讀一遍我之前寫過一篇文章
談一談javascript作用域
我們對上面的問題再次分析,for循環同步執行,在for循環內部遇到了setTimeout,setTimeout是異步執行的,所以加入了異步隊列,當同步的for循環執行完畢后,再去執行異步隊列,setTimeout中有唯一的一個參數數index
方式三可行,是因為let是塊級作用域,每次for執行都會創建新的變量index,for循環執行完畢后,異步執行之前,創建了5個獨立的作用域,5個index變量,分別是0,1,2,3,4,相互獨立,互不影響,輸出了預期的結果
如果說每次循環都會生成一個獨立的作用域用來保存index,問題就會得到解決,所以,我們通過閉包來實現
????const?array = [1,?2,?3,?4,?5]
????function?foo()?{
??????for?(var?index =?0; index < array.length; index++) {
????????function?fun(j)?{
??????????setTimeout(function?()?{
????????????console.log(j);
??????????},?1000?* j);
????????}
????????fun(index)
??????}
????}
????foo()
setTimeout中的匿名回調函數中引用了函數fun中的局部變量j,所以當fun執行完畢后,變量j不會被釋放,這就形成了閉包
當然我們可以對此進行一下優化
????const?array = [1,?2,?3,?4,?5]
????function?foo()?{
??????for?(var?index =?0; index < array.length; index++) {
????????(function(j)?{
??????????setTimeout(function?()?{
????????????console.log(j);
??????????},?1000?* j);
????????})(index)
??????}
????}
????foo()
將foo函數改為匿名的立即執行函數,結果是相同的
總結
for循環本身是同步執行的,當在for循環中遇到了異步邏輯,異步就會進入異步隊列,當for循環執行結束后,才會執行異步隊列 當異步函數依賴于for循環中的索引時(一定是存在依賴關系的,不然不會再循環中調動異步函數)要考慮作用域的問題,
在ES6中使用let是最佳的選擇
當使用var時,可以考慮再引入一個索引來替代for循環中的索引,新的索引邏輯要在異步中處理
也可以使用閉包,模擬實現let 在實際開發過程中,循環調用異步函數,比demo要復雜,可能還會出現if和else判斷等邏輯,具體的我們下次再續
總結
以上是生活随笔為你收集整理的stm32怎么调用for循环内部的变量_循环中的异步amp;amp;循环中的闭包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 王者荣耀转会名单是什么
- 下一篇: ni软件管理器_Multisim 12.