文將為您提供對(duì)如何迭代JavaScript中的Array數(shù)據(jù)結(jié)構(gòu)的扎實(shí)理解。無(wú)論您是剛剛開(kāi)始學(xué)習(xí)JavaScript還是在這里學(xué)習(xí)復(fù)習(xí),任何一種方式都將為您帶來(lái)價(jià)值。本文將引導(dǎo)您完成使用最廣泛的JavaScript概念之一。
上面是一個(gè)用于存儲(chǔ)多個(gè)值的JavaScript數(shù)組。這是數(shù)組的最簡(jiǎn)單形式之一。它在數(shù)組內(nèi)部包含4個(gè)“元素”,所有字符串。如您所見(jiàn),每個(gè)元素都用逗號(hào)分隔。此示例數(shù)組包含不同品牌的汽車(chē),并且可以用cars變量引用。
我們可以通過(guò)多種方法來(lái)迭代此數(shù)組。JavaScript具有令人難以置信的豐富功能,因此我們可以選擇最佳的方法來(lái)解決問(wèn)題。
這是解決JavaScript中數(shù)組迭代的方法:
1、重點(diǎn)介紹5種遍歷數(shù)組的常用方法
2、對(duì)每種迭代方法顯示一些見(jiàn)解
3、提供一些代碼,您也可以使用它進(jìn)行測(cè)試!
什么是For循環(huán)?維基百科將For循環(huán)定義為:
“在計(jì)算機(jī)科學(xué)中,for循環(huán)(或簡(jiǎn)稱(chēng)為for循環(huán))是用于指定迭代的控制流 語(yǔ)句,該語(yǔ)句允許重復(fù)執(zhí)行代碼。”for循環(huán)是一種重復(fù)執(zhí)行代碼的方法。console.log(“hi”)您可以將其包裝在for循環(huán)中,而不必鍵入5次。在第一個(gè)示例中,我們將學(xué)習(xí)如何遍歷上面看到的cars數(shù)組,并打印出每個(gè)元素。迭代器或計(jì)數(shù)器將在第一個(gè)索引“ Tesla”處開(kāi)始,并在最后一個(gè)“ Audi”處結(jié)束。它遍歷數(shù)組并一次打印一個(gè)元素。
輸出:
深入研究代碼,我們將三個(gè)選項(xiàng)傳遞給for循環(huán)
1、迭代器變量- let i = 0;
2、迭代器應(yīng)在何處停止- i < card.length
3、每個(gè)循環(huán)增加多少迭代器- i++
此循環(huán)從開(kāi)始于0,每個(gè)循環(huán)將變量增加一個(gè),并在我們擊中數(shù)組中的最后一個(gè)元素時(shí)停止。傳統(tǒng)的for循環(huán)的主要好處是您擁有更多的控制權(quán)。可以訪問(wèn)數(shù)組中的不同元素,或者以復(fù)雜的方式遍歷數(shù)組以解決復(fù)雜的問(wèn)題。例如,使用傳統(tǒng)的for循環(huán)可以很容易地跳過(guò)數(shù)組中的所有其他元素。
什么是forEach方法?該forEach方法用于為數(shù)組的每個(gè)元素執(zhí)行一個(gè)函數(shù)。如果數(shù)組的長(zhǎng)度是“未知”或保證會(huì)改變,則此方法是一個(gè)不錯(cuò)的選擇。此方法只能與數(shù)組,集合和映射一起使用。
forEach循環(huán)的最大好處是即使數(shù)組的大小可能會(huì)增加,也能夠訪問(wèn)每個(gè)項(xiàng)目。它是適用于許多用例的可擴(kuò)展解決方案,比傳統(tǒng)的for循環(huán)更易于閱讀和理解,因?yàn)槲覀冎牢覀儗?duì)每個(gè)元素進(jìn)行精確的迭代一次。
什么是While循環(huán)?維基百科將While循環(huán)定義為:“ while循環(huán)是一個(gè)控制流 語(yǔ)句,它允許根據(jù)給定的布爾條件重復(fù)執(zhí)行代碼。在同時(shí)循環(huán)可以被認(rèn)為是一個(gè)重復(fù)的if語(yǔ)句。”一while環(huán)是,如果一個(gè)條件是真還是假反復(fù)執(zhí)行代碼來(lái)檢查的方式。因此,我們可以使用while循環(huán),而不是使用帶有嵌套if語(yǔ)句的for循環(huán)。或者,如果我們無(wú)法找到數(shù)組的長(zhǎng)度,則while循環(huán)是一個(gè)不錯(cuò)的選擇。while循環(huán)通常由計(jì)數(shù)器控制。在下面的示例中,我們顯示了遍歷數(shù)組的基本while循環(huán)。關(guān)鍵是要控制正在創(chuàng)建的while循環(huán)。
While循環(huán)示例(良好):
輸出:
while循環(huán)的if語(yǔ)句為i < 5,或大聲說(shuō)“ i小于5”。i每次循環(huán)運(yùn)行時(shí),變量都會(huì)增加。簡(jiǎn)單來(lái)說(shuō),這意味著i每次循環(huán)執(zhí)行完整迭代時(shí),都會(huì)將1加到變量中。在第一次迭代中,i它等于0,然后在控制臺(tái)上打印“ 0”。使用while循環(huán)的最大風(fēng)險(xiǎn)是編寫(xiě)從未滿(mǎn)足的條件。在現(xiàn)實(shí)世界中,這種情況經(jīng)常發(fā)生,有人編寫(xiě)了while循環(huán),卻忘記測(cè)試他們的循環(huán),并且在代碼庫(kù)中引入了無(wú)限循環(huán)。當(dāng)永不滿(mǎn)足條件時(shí),將發(fā)生無(wú)限循環(huán),并且該循環(huán)將永遠(yuǎn)運(yùn)行。這通常會(huì)導(dǎo)致更改中斷,然后導(dǎo)致整個(gè)軟件應(yīng)用程序中斷并停止工作。警告:請(qǐng)勿運(yùn)行此代碼。
輸出:結(jié)果可能會(huì)有所不同。
什么是map?維基百科將map定義為:“在許多編程語(yǔ)言中,map是將給定函數(shù)應(yīng)用于函子的每個(gè)元素的高階函數(shù)的名稱(chēng),例如list,以相同順序返回結(jié)果列表。以功能形式考慮時(shí),它通常被稱(chēng)為“ 適用于所有人 ”。它是如何工作的?mapJavaScript中的函數(shù)將函數(shù)應(yīng)用于數(shù)組內(nèi)的每個(gè)元素。請(qǐng)花一點(diǎn)時(shí)間重新閱讀該句子。然后,該map函數(shù)返回一個(gè)新數(shù)組,并將該函數(shù)應(yīng)用于該數(shù)組中的每個(gè)元素。
map示例:
輸出:
我們已將該map函數(shù)應(yīng)用于包含四個(gè)1的數(shù)組。然后,該函數(shù)將每個(gè)元素乘以2,即x * 2,并返回一個(gè)新數(shù)組。然后將新數(shù)組存儲(chǔ)在results變量中。
通過(guò)查看我們的輸出,我們可以看到此方法成功完成。數(shù)組中的每個(gè)元素都已乘以2。在某些情況下,該方法可以替代循環(huán),并且功能非常強(qiáng)大。
您已經(jīng)了解了五種遍歷JavaScript中數(shù)組的不同方法。這些是基本的構(gòu)建塊,可幫助您成功完成JavaScript編程之旅。您還將接觸到高級(jí)概念map,該概念經(jīng)常在大型軟件應(yīng)用程序中使用。因此,您將如何在項(xiàng)目中使用數(shù)組?您覺(jué)得哪種迭代方法最令人興奮?
謝謝閱讀!如果您喜歡我的文章,請(qǐng)關(guān)注我和/或給我發(fā)送消息!
Spring Boot編程中,我們可以使用多種方式返回HTML頁(yè)面。下面是幾種常用的方法:
Thymeleaf是一款流行的模板引擎,Spring Boot默認(rèn)集成了它。使用Thymeleaf可以方便地生成HTML頁(yè)面,并且支持模板繼承、條件判斷、循環(huán)等常見(jiàn)功能。在Controller中,我們可以將模型數(shù)據(jù)傳遞給Thymeleaf模板,然后渲染生成HTML頁(yè)面。
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("name", "world");
return "hello";
}
上面的代碼中,我們將一個(gè)名為"hello"的Thymeleaf模板返回給客戶(hù)端,并且傳遞了一個(gè)名為"name"的模型屬性。在模板中,可以使用Thymeleaf的語(yǔ)法進(jìn)行渲染。
優(yōu)點(diǎn):
缺點(diǎn):
Freemarker是另一款常見(jiàn)的模板引擎,它也支持模板繼承、條件判斷、循環(huán)等功能。在Spring Boot中,我們可以使用Freemarker作為模板引擎,生成HTML頁(yè)面。
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("name", "world");
return "hello";
}
上面的代碼與Thymeleaf的使用方式類(lèi)似。只需要將返回值改為模板的名稱(chēng)即可。
優(yōu)點(diǎn):
缺點(diǎn):
JSP(JavaServer Pages)是一種常見(jiàn)的Java Web頁(yè)面技術(shù),也可以在Spring Boot中使用。在使用JSP時(shí),需要在pom.xml文件中添加對(duì)jsp-api和jstl的依賴(lài),并且需要配置視圖解析器。
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("name", "world");
return "hello";
}
上面的代碼中,返回值為"hello",這意味著Spring Boot將查找名為"hello.jsp"的JSP文件,并且將模型數(shù)據(jù)傳遞給它進(jìn)行渲染。
優(yōu)點(diǎn):
缺點(diǎn):
在前后端分離的架構(gòu)中,前端和后端是獨(dú)立的,可以分別開(kāi)發(fā)和部署。前端使用JavaScript等技術(shù)生成HTML頁(yè)面,后端則提供API接口,返回JSON等數(shù)據(jù)格式。前端通過(guò)調(diào)用后端提供的API接口獲取數(shù)據(jù),并渲染生成HTML頁(yè)面。
@GetMapping("/hello")
public ResponseEntity<Map<String, Object>> hello() {
Map<String, Object> data = new HashMap<>();
data.put("name", "world");
return ResponseEntity.ok(data);
}
上面的代碼中,我們返回一個(gè)Map對(duì)象,包含一個(gè)名為"name"的屬性。在前端中,可以通過(guò)調(diào)用"/hello"接口獲取數(shù)據(jù),并渲染生成HTML頁(yè)面。
優(yōu)點(diǎn):
缺點(diǎn):
在使用Spring Boot返回HTML頁(yè)面時(shí),可能會(huì)出現(xiàn)一些常見(jiàn)問(wèn)題,下面是一些解決方法:
@RequestMapping(value = "/hello", produces = "text/html;charset=UTF-8")
選擇哪種方法返回HTML頁(yè)面取決于具體的需求和項(xiàng)目情況。在選擇方法時(shí),需要考慮開(kāi)發(fā)成本、渲染速度、易用性等因素,并且需要注意常見(jiàn)問(wèn)題,避免出現(xiàn)不必要的錯(cuò)誤。
armonyOS 2提供了兩種應(yīng)用開(kāi)發(fā)語(yǔ)言:Java和JS。Java線程特性能夠讓多任務(wù)并行,充分利用硬件資源開(kāi)發(fā)出高性能的應(yīng)用。而JS卻是一個(gè)單線程語(yǔ)言,無(wú)法像Java一樣創(chuàng)建新的Thread,用JS語(yǔ)言開(kāi)發(fā)是否會(huì)導(dǎo)致硬件資源無(wú)法充分利用的情況呢?
本文給大家介紹“ACE JS的單線程異步機(jī)制”就是解決這個(gè)問(wèn)題的。然而,說(shuō)到 “單線程”與“異步”,大家可能會(huì)比較疑惑,因?yàn)閱尉€程和異步在概念上是沖突的,單線程無(wú)法做到多任務(wù)并發(fā),也就不會(huì)存在異步這種通信機(jī)制。
確實(shí),JS語(yǔ)言本身是無(wú)法實(shí)現(xiàn)異步的,但是ACE JS框架卻提供了多線程的宿主環(huán)境,通過(guò)消息通信機(jī)制讓JS語(yǔ)言有了異步的屬性,下面我們來(lái)詳細(xì)描述其原理。
使用JS開(kāi)發(fā)HarmonyOS應(yīng)用,使用的開(kāi)發(fā)框架名為ACE(Ability Cross-Platform Environment),該框架適用于手機(jī)、平板、智慧屏、智慧表、車(chē)機(jī)等設(shè)備,具備“一次開(kāi)發(fā),多端部署”的能力。
ACE框架包括應(yīng)用層(Application)、前端框架層(Framework)、引擎層(Engine)和平臺(tái)適配層(Porting Layer),如下圖所示:
?● Application
應(yīng)用層表示開(kāi)發(fā)者使用JS UI框架開(kāi)發(fā)的FA應(yīng)用,這里的FA應(yīng)用特指JS FA應(yīng)用。
● Framework
前端框架層主要完成前端頁(yè)面解析,以及提供MVVM(Model-View-ViewModel)開(kāi)發(fā)模式、頁(yè)面路由機(jī)制和自定義組件等能力。
● Engine
引擎層主要提供動(dòng)畫(huà)解析、DOM(Document Object Model)樹(shù)構(gòu)建、布局計(jì)算、渲染命令構(gòu)建與繪制、事件管理等能力。
● Porting Layer
適配層主要完成對(duì)平臺(tái)層進(jìn)行抽象,提供抽象接口,可以對(duì)接到系統(tǒng)平臺(tái)。比如:事件對(duì)接、渲染管線對(duì)接和系統(tǒng)生命周期對(duì)接等。
?
?
每個(gè)HarmonyOS JS應(yīng)用,都是通過(guò)上圖所示的ACE開(kāi)發(fā)框架進(jìn)行加載渲染的。ACE開(kāi)發(fā)框架包含了JS線程、UI線程、GPU線程、IO線程,并且在ACE框架外還會(huì)存在一類(lèi)后臺(tái)任務(wù)線程。
其中GPU線程與IO線程主要是ACE框架初始化與頁(yè)面加載渲染的過(guò)程需要的,為ACE框架內(nèi)部的專(zhuān)有線程,不會(huì)被應(yīng)用直接操作到,應(yīng)用不需要特別關(guān)注;UI線程、JS線程和后臺(tái)任務(wù)線程會(huì)與應(yīng)用開(kāi)發(fā)代碼相關(guān),后面著重分析這三個(gè)線程的作用和關(guān)系。
● UI線程:負(fù)責(zé)應(yīng)用界面的繪制刷新,與應(yīng)用的進(jìn)程號(hào)相同,又叫主線程。如果開(kāi)發(fā)JS+JAVA的混合編程,JAVA PA(Particle Ability)的onStart/onConnect等Ability生命周期回調(diào)便是運(yùn)行在主線程,若在這些生命周期回調(diào)上執(zhí)行耗時(shí)操作則會(huì)導(dǎo)致JS UI的繪制刷新卡住。
● JS線程:應(yīng)用的JS代碼會(huì)被JS引擎解析執(zhí)行,并運(yùn)行在JS線程上,而JS又是單線程語(yǔ)言,所以目前我們工程中看到的所有的JS代碼都會(huì)執(zhí)行在這個(gè)進(jìn)程下唯一的JS線程上。
● 后臺(tái)任務(wù)線程:這里是對(duì)ACE框架外部的后臺(tái)線程的一個(gè)統(tǒng)稱(chēng),并不單指一個(gè)線程,也并不唯一。后臺(tái)任務(wù)線程包含了Java PA線程、文件操作API、網(wǎng)絡(luò)訪問(wèn)API內(nèi)部實(shí)現(xiàn)等相關(guān)線程。
下面我們結(jié)合測(cè)試代碼來(lái)看一下這3個(gè)線程之間的關(guān)系。
為了驗(yàn)證JS線程與UI線程的關(guān)系,我們準(zhǔn)備了一個(gè)實(shí)驗(yàn)性質(zhì)的Demo,主要代碼以及運(yùn)行過(guò)程的Log如下:
首先我們?cè)贗DE建立一個(gè)Empty Ablity(JS)模板的HelloWorld工程,在生命周期、按鈕響應(yīng)回調(diào)方法里增加Log以觀察線程情況。剛創(chuàng)建的app.js中Application生命周期默認(rèn)已經(jīng)有Log,無(wú)需額外添加。
我們只需要在主界面index.js文件中onInit增加日志:
console.info(<span class="hljs-string">'page.default onInit'</span>);復(fù)制
然后在index.hml中增加一個(gè)button以及會(huì)一直進(jìn)行動(dòng)畫(huà)的progress組件:
<button id='button1' onclick="onButtonClick">I'm a button</button>
<progress type="circular"/>復(fù)制
最后在index.js中增加按鈕點(diǎn)擊響應(yīng)事件以及Log,并且嘗試sleep阻塞js線程:
function sleep(delay) {
for (var t = Date.now(); Date.now() - t <= delay; );
}
onButtonClick() {
console.info('onButtonClick begin');
sleep(1000);
console.info('onButtonClick end');
}復(fù)制
將應(yīng)用運(yùn)行起來(lái),點(diǎn)擊兩次按鈕,得到如下Log:
?
?
從輸出的Log中,我們可以看到這個(gè)JS FA進(jìn)程號(hào)為22592,也就是說(shuō)UI線程是22592;生命周期回調(diào)以及按鈕響應(yīng)均在24077線程,這個(gè)就是JS線程,所以JS線程與UI線程不是同一個(gè)線程。
并且我們嘗試通過(guò)sleep方法阻塞JS線程,想觀察JS線程阻塞是否會(huì)影響到UI線程的刷新。最終得出的結(jié)論是無(wú)論JS線程sleep多長(zhǎng)時(shí)間,UI界面上的progress組件動(dòng)畫(huà)一直會(huì)不斷刷新,按鈕也會(huì)有按壓效果變化,所以我們可以推測(cè)JS線程與UI線程的相互調(diào)用應(yīng)該是通過(guò)某種消息機(jī)制完成的,而不是阻塞式的調(diào)用。
ACE JS框架提供了JS FA(Feature Ability)調(diào)用Java PA(Particle Ability)的機(jī)制,該機(jī)制提供了一種通道來(lái)傳遞方法調(diào)用、處理數(shù)據(jù)返回以及訂閱事件上報(bào)。我們同樣制作一個(gè)Demo來(lái)驗(yàn)證JS線程與Java PA線程的關(guān)系:
在JS中,我們通過(guò)FeatureAbility.callAbility拉起并調(diào)用了名為一個(gè)類(lèi)名為ServiceAbility的Java PA,并拿到返回結(jié)果:
var action = {};
action.bundleName = <span class="hljs-string">'com.blancwu.test'</span>;
action.abilityName = <span class="hljs-string">'com.blancwu.test.ServiceAbility'</span>;
action.messageCode = <span class="hljs-number">1001</span>;
action.abilityType = <span class="hljs-number">0</span>;
action.syncOption = <span class="hljs-number">0</span>;
console.info(<span class="hljs-string">'FeatureAbility.callAbility begin'</span> + JSON.stringify(action));
FeatureAbility.callAbility(action).then(function (value) {
console.info(<span class="hljs-string">'FeatureAbility.callAbility async result '</span> + JSON.stringify(value));
})
console.info(<span class="hljs-string">'FeatureAbility.callAbility end'</span> + JSON.stringify(action));復(fù)制
在ServiceAbility的onRemoteRequest中增加Log輸出,并sleep 1秒鐘,以便觀察線程情況與之間關(guān)系:
@Override
public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
HiLog.info(LABEL_LOG, "onRemoteRequest begin " + code);
if (code == 1001) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("result", 1);
reply.writeString(ZSONObject.toZSONString(result));
}
HiLog.info(LABEL_LOG, "onRemoteRequest end " + code);
return super.onRemoteRequest(code, data, reply, option);
}復(fù)制
以上代碼完成后,我們進(jìn)行執(zhí)行,得到的Log如下:
?
?
我們觀察到本次運(yùn)行主進(jìn)程(UI線程)號(hào)為4133,JS代碼執(zhí)行在JS線程5887,Java PA響應(yīng)onRemoteRequest執(zhí)行在另一個(gè)后臺(tái)任務(wù)線程5837。通過(guò)Log我們看到onRemoteRequst即使阻塞了后臺(tái)任務(wù)線程1s也不會(huì)影響JS線程的并行執(zhí)行以及主線程(UI線程)上動(dòng)畫(huà)的刷新,做到了JS線程與后臺(tái)任務(wù)線程異步地執(zhí)行事務(wù)。
上面從代碼實(shí)驗(yàn)角度觀察到了JS線程與其他線程的異步關(guān)系,那么JS線程是怎么處理來(lái)自其他多個(gè)線程的調(diào)用的呢?我們先來(lái)看一下傳統(tǒng)的瀏覽器環(huán)境下的機(jī)制:
?
?
上圖中,JS線程中的函數(shù)調(diào)用會(huì)存在于棧(stack)中,棧中的函數(shù)可以調(diào)用瀏覽器環(huán)境提供的WebAPIs,包含了DOM、ajax、timeout等API,這些API會(huì)在瀏覽器環(huán)境提供的另外一個(gè)外部線程執(zhí)行,執(zhí)行完成后會(huì)在任務(wù)隊(duì)列(callback queue)中加入對(duì)應(yīng)的回調(diào)事件(如onClick、onLoad、onDone)。當(dāng)棧中的代碼執(zhí)行完畢,即棧清空后,JS線程又會(huì)通過(guò)event loop取出任務(wù)隊(duì)列中的下一個(gè)任務(wù)進(jìn)行執(zhí)行,以此類(lèi)推完成整個(gè)的程序執(zhí)行。更具體的機(jī)制可以去看阮一峰老師介紹JS EventLoop的文章:
● JS EventLoop介紹
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
HarmonyOS ACE開(kāi)發(fā)框架同樣遵循上述最基本的EventLoop調(diào)度機(jī)制,并且提供了更多的機(jī)制和API,讓業(yè)務(wù)邏輯可以在外部線程執(zhí)行,包含了上面提到的Java PA以及異步回調(diào)的系統(tǒng)能力API。其中,異步回調(diào)的系統(tǒng)能力API包含如文件系統(tǒng)操作和網(wǎng)絡(luò)操作等,具體大家可以按照我們實(shí)驗(yàn)Demo的方法去嘗試一下。
● 參考
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-file-storage-0000000000629445
目前ACE JS應(yīng)用內(nèi)實(shí)現(xiàn)多線程的最佳方式是通過(guò)混合編程調(diào)用Java PA方式,但未來(lái)純JS應(yīng)用一定會(huì)越來(lái)越多,那么,只支持單線程的JS ACE框架的異步API能解決各種復(fù)雜場(chǎng)景的問(wèn)題嗎?
單線程的JS加上異步API能夠很好解決單個(gè)I/O阻塞的問(wèn)題,但是如果遇到大量的I/O事件,比如批刪除大量文件,通過(guò)for循環(huán)發(fā)起了大量異步任務(wù),也會(huì)降低執(zhí)行效率,甚至阻塞其他異步任務(wù)的執(zhí)行。并且如果要使用JS語(yǔ)言開(kāi)發(fā)計(jì)算密集型的任務(wù),也無(wú)法在唯一的JS線程上進(jìn)行。
這時(shí)就需要一個(gè)真正的JS多線程處理機(jī)制了,雖然目前HarmonyOS 2還未支持,但未來(lái)HarmonyOS會(huì)考慮規(guī)劃出與HTML5類(lèi)似提供支持WebWorker機(jī)制,支持開(kāi)發(fā)出多線程的JS代碼,提供給應(yīng)用開(kāi)發(fā)者更多的發(fā)揮空間。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。