摘要:原文鏈接在這之前先要了解一下循環(huán)中和的區(qū)別是函數(shù)級(jí)作用域或者全局作用域,是塊級(jí)作用域看一個(gè)例子循環(huán)中的邏輯代碼函數(shù)下的輸出,全局下的不存在現(xiàn)在我們把換為循環(huán)中的邏輯代碼報(bào)錯(cuò)了,不在函數(shù)作用域下,當(dāng)然肯定也不會(huì)再全局下因?yàn)楹偷倪@個(gè)區(qū)別當(dāng)然和的
原文鏈接
在這之前先要了解一下
var 是函數(shù)級(jí)作用域或者全局作用域,let是塊級(jí)作用域
看一個(gè)例子
function foo() { for (var index = 0; index < array.length; index++) { //..循環(huán)中的邏輯代碼 } console.log(index);//=>5 } foo() console.log(index)//Uncaught ReferenceError: index is not defined
foo函數(shù)下的index輸出5,全局下的index不存在
現(xiàn)在我們把var 換為let
function foo() { for (let index = 0; index < array.length; index++) { //..循環(huán)中的邏輯代碼 } console.log(index)//Uncaught ReferenceError: index is not defined } foo()
報(bào)錯(cuò)了,index不在foo函數(shù)作用域下,當(dāng)然肯定也不會(huì)再全局下
因?yàn)関ar和let的這個(gè)區(qū)別(當(dāng)然var和let的區(qū)別不止于此)所以導(dǎo)致了下面的這個(gè)問(wèn)題
關(guān)于var的
const array = [1, 2, 3, 4, 5] function foo() { for (var index = 0; index < array.length; index++) { setTimeout(() => { console.log(index); }, 1000); } } foo()
看下輸出
關(guān)于let的
const array = [1, 2, 3, 4, 5] function foo() { for (let index = 0; index < array.length; index++) { setTimeout(() => { console.log(index); }, 1000); } } foo()
看下輸出
因?yàn)関ar和let 在作用域上的差別,所以到這了上面的問(wèn)題
使用var 定義變量的時(shí)候,作用域是在foo函數(shù)下,在for循環(huán)外部,在整個(gè)循環(huán)中是全局的,每一次的循環(huán)實(shí)際上是為index賦值,循環(huán)一次賦值一次,5次循環(huán)完成,index最后的結(jié)果賦值就為5;就是被最終賦值的index,就是5;
let的作用局的塊級(jí)作用局,index的作用域在for循環(huán)內(nèi)部,即每次循環(huán)的index的作用域就是本次循環(huán),下一次循環(huán)重新定義變量index;所以index每次循環(huán)的輸出都不同
這里還有另外一個(gè)問(wèn)題,setTimeout,這是一個(gè)異步,這就是我們今天要討論的
setTimeout(func,time)是在time(毫秒單位)時(shí)間后執(zhí)行func函數(shù)。瀏覽器引擎按順序執(zhí)行程序,遇到setTimeout會(huì)將func函數(shù)放到執(zhí)行隊(duì)列中,等到主程序執(zhí)行完畢之后,才開(kāi)始從執(zhí)行隊(duì)列(隊(duì)列中可能有多個(gè)待執(zhí)行的func函數(shù))中按照time延時(shí)時(shí)間的先后順序取出來(lái)func并執(zhí)行。即使time=0,也會(huì)等主程序運(yùn)行完之后,才會(huì)執(zhí)行。
一個(gè)需求,一個(gè)數(shù)組array[1,2,3,4,5],循環(huán)打印,間隔1秒上面的let是循環(huán)打印了12345,但是不是間隔1s打印的,是在foo函數(shù)執(zhí)行1s后,同時(shí)打印的
方式一 放棄for循環(huán),使用setIntervalfunction 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()
我們上面說(shuō)到,當(dāng)for循環(huán)遇到了var,變量index的作用域在foo函數(shù)下,循環(huán)一次賦值一次,5次循環(huán)完成,index最后的結(jié)果賦值就為5;就是被最終賦值的index,就是5;
方式二,引入全局變量代碼執(zhí)行順序是,先同步執(zhí)行for循環(huán),再執(zhí)行異步隊(duì)列,在for循環(huán)執(zhí)行完畢后,異步隊(duì)列開(kāi)始執(zhí)行之前,index經(jīng)過(guò)for循環(huán)的處理,變成了5。
所以我們引入一個(gè)全局變量j,使j在for循環(huán)執(zhí)行完畢后,異步隊(duì)列開(kāi)始執(zhí)行之前,依然是0,在異步執(zhí)行時(shí)進(jìn)行累加
var j = 0; for (var index = 0; index < array.length; index++) { setTimeout(() => { console.log(j); j++; }, 1000 * index) }方式三 for循環(huán)配合setTimeout(常規(guī)思路,不贅述,面試必備技能)
const array = [1, 2, 3, 4, 5] function foo() { for (let index = 0; index < array.length; index++) { setTimeout(() => { console.log(index); }, 1000*index); } } foo()方式四,通過(guò)閉包實(shí)現(xiàn)
開(kāi)始討論方式四之前我推薦先閱讀一遍我之前寫過(guò)一篇文章
談一談javascript作用域
我們對(duì)上面的問(wèn)題再次分析,for循環(huán)同步執(zhí)行,在for循環(huán)內(nèi)部遇到了setTimeout,setTimeout是異步執(zhí)行的,所以加入了異步隊(duì)列,當(dāng)同步的for循環(huán)執(zhí)行完畢后,再去執(zhí)行異步隊(duì)列,setTimeout中有唯一的一個(gè)參數(shù)數(shù)index
方式三可行,是因?yàn)閘et是塊級(jí)作用域,每次for執(zhí)行都會(huì)創(chuàng)建新的變量index,for循環(huán)執(zhí)行完畢后,異步執(zhí)行之前,創(chuàng)建了5個(gè)獨(dú)立的作用域,5個(gè)index變量,分別是0,1,2,3,4,相互獨(dú)立,互不影響,輸出了預(yù)期的結(jié)果
如果說(shuō)每次循環(huán)都會(huì)生成一個(gè)獨(dú)立的作用域用來(lái)保存index,問(wèn)題就會(huì)得到解決,所以,我們通過(guò)閉包來(lái)實(shí)現(xiàn)
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中的匿名回調(diào)函數(shù)中引用了函數(shù)fun中的局部變量j,所以當(dāng)fun執(zhí)行完畢后,變量j不會(huì)被釋放,這就形成了閉包
當(dāng)然我們可以對(duì)此進(jìn)行一下優(yōu)化
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函數(shù)改為匿名的立即執(zhí)行函數(shù),結(jié)果是相同的
總結(jié)for循環(huán)本身是同步執(zhí)行的,當(dāng)在for循環(huán)中遇到了異步邏輯,異步就會(huì)進(jìn)入異步隊(duì)列,當(dāng)for循環(huán)執(zhí)行結(jié)束后,才會(huì)執(zhí)行異步隊(duì)列
當(dāng)異步函數(shù)依賴于for循環(huán)中的索引時(shí)(一定是存在依賴關(guān)系的,不然不會(huì)再循環(huán)中調(diào)動(dòng)異步函數(shù))要考慮作用域的問(wèn)題,
在ES6中使用let是最佳的選擇,
當(dāng)使用var時(shí),可以考慮再引入一個(gè)索引來(lái)替代for循環(huán)中的索引,新的索引邏輯要在異步中處理
也可以使用閉包,模擬實(shí)現(xiàn)let
在實(shí)際開(kāi)發(fā)過(guò)程中,循環(huán)調(diào)用異步函數(shù),比demo要復(fù)雜,可能還會(huì)出現(xiàn)if和else判斷等邏輯,具體的我們下次再續(xù)
參考
通過(guò)for循環(huán)每隔兩秒按順序打印出arr中的數(shù)字
setTimeOut和閉包
《你不知道的JavaScript》上卷
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/102334.html
一、我們先說(shuō)說(shuō)javascript的作用域 ①全局變量-函數(shù)體外部進(jìn)行聲明 ②局部變量-函數(shù)體內(nèi)部進(jìn)行聲明 1)函數(shù)級(jí)作用域 javascript語(yǔ)言中局部變量不同于C#、Java等高級(jí)語(yǔ)言,在這些高級(jí)語(yǔ)言內(nèi)部,采用的塊級(jí)作用域中會(huì)聲明新的變量,這些變量不會(huì)影響到外部作用域。 而javascript則采用的是函數(shù)級(jí)作用域,也就是說(shuō)js創(chuàng)建作用域的單位是函數(shù)。 例如: 在C#當(dāng)中我...
摘要:今天同學(xué)去面試,做了兩道面試題全部做錯(cuò)了,發(fā)過(guò)來(lái)給道典型的面試題前端掘金在界中,開(kāi)發(fā)人員的需求量一直居高不下。 排序算法 -- JavaScript 標(biāo)準(zhǔn)參考教程(alpha) - 前端 - 掘金來(lái)自《JavaScript 標(biāo)準(zhǔn)參考教程(alpha)》,by 阮一峰 目錄 冒泡排序 簡(jiǎn)介 算法實(shí)現(xiàn) 選擇排序 簡(jiǎn)介 算法實(shí)現(xiàn) ... 圖例詳解那道 setTimeout 與循環(huán)閉包的經(jīng)典面...
摘要:該對(duì)象包含了函數(shù)的所有局部變量命名參數(shù)參數(shù)集合以及,然后此對(duì)象會(huì)被推入作用域鏈的前端。如果整個(gè)作用域鏈上都無(wú)法找到,則返回。此時(shí)的作用域鏈包含了兩個(gè)對(duì)象的活動(dòng)對(duì)象和對(duì)象。 前端學(xué)習(xí):教程&開(kāi)發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:閉包 JavaScript-閉包 閉包(closure)是一個(gè)讓人又愛(ài)又恨的somet...
摘要:內(nèi)存回收內(nèi)存泄漏前言最近在細(xì)讀高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方一筆帶過(guò),所以用自己所理解的,嘗試細(xì)致解讀下。內(nèi)存回收在談內(nèi)存泄漏之前,首先,先了解下的內(nèi)存回收機(jī)制。 內(nèi)存回收 && 內(nèi)存泄漏 前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方一筆帶過(guò),所以用自己所理解的,嘗試細(xì)致解讀下。如有紕漏或錯(cuò)誤,會(huì)非常感謝您的指出。文中絕大部分內(nèi)容...
學(xué)習(xí)一門知識(shí),有些內(nèi)容必須要提前明白,比如在學(xué)習(xí)js中同步異步的問(wèn)題前,需要明白,js是單線程的,為什么它得是單線程的呢?現(xiàn)在先從它應(yīng)用的場(chǎng)景來(lái)說(shuō),就是用來(lái)讓用戶與頁(yè)面進(jìn)行交互的吧。假如有js是多線程的,那在這個(gè)線程里面,用戶點(diǎn)擊某個(gè)按鈕會(huì)增加一個(gè)DOM節(jié)點(diǎn),在另一個(gè)線程里面,用戶點(diǎn)擊這個(gè)按鈕又會(huì)刪除一個(gè)DOM節(jié)點(diǎn),那么此時(shí)js就不知道該聽(tīng)誰(shuí)的了。這就是為什么會(huì)出現(xiàn)同步異步。假設(shè)沒(méi)有異步,那么...
閱讀 3444·2021-09-08 10:46
閱讀 1180·2019-08-30 13:17
閱讀 2358·2019-08-30 13:05
閱讀 1200·2019-08-29 15:29
閱讀 2882·2019-08-29 11:31
閱讀 533·2019-08-26 12:13
閱讀 1532·2019-08-26 11:42
閱讀 1817·2019-08-23 18:37