for
成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供青神網(wǎng)站建設(shè)、青神做網(wǎng)站、青神網(wǎng)站設(shè)計(jì)、青神網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、青神企業(yè)網(wǎng)站模板建站服務(wù),10年青神做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
for遍歷界最早出現(xiàn)的,能滿足開發(fā)人員的絕大多數(shù)的需求。
分別是for
, foreach
, map
, for...in
, for...of
// 遍歷數(shù)組 let arr = [1,2,3]; for(let i = 0;i < arr.length;i++){ console.log(i) // 索引,數(shù)組下標(biāo) console.log(arr[i]) // 數(shù)組下標(biāo)所對(duì)應(yīng)的元素 } // 遍歷對(duì)象 let profile = {name:"April",nickname:"二十七刻",country:"China"}; for(let i = 0, keys=Object.keys(profile); i < keys.length;i++){ console.log(keys[i]) // 對(duì)象的鍵值 console.log(profile[keys[i]]) // 對(duì)象的鍵對(duì)應(yīng)的值 } // 遍歷字符串 let str = "abcdef"; for(let i = 0;i < str.length ;i++){ console.log(i) // 索引 字符串的下標(biāo) console.log(str[i]) // 字符串下標(biāo)所對(duì)應(yīng)的元素 } // 遍歷DOM 節(jié)點(diǎn) let articleParagraphs = document.querySelectorAll('.article > p'); for(let i = 0;iforEach
我是ES5版本發(fā)布的。按升序?yàn)閿?shù)組中含有效值的每一項(xiàng)執(zhí)行一次 callback 函數(shù),那些已刪除或者未初始化的項(xiàng)將被跳過(例如在稀疏數(shù)組上)。我是 for 循環(huán)的加強(qiáng)版。
// 遍歷數(shù)組 let arr = [1,2,3]; arr.forEach(i => console.log(i)) // logs 1 // logs 2 // logs 3 // 直接輸出了數(shù)組的元素 //遍歷對(duì)象 let profile = {name:"April",nickname:"二十七刻",country:"China"}; let keys = Object.keys(profile); keys.forEach(i => { console.log(i) // 對(duì)象的鍵值 console.log(profile[i]) // 對(duì)象的鍵對(duì)應(yīng)的值 })map
我也是ES5版本發(fā)布的,我可以創(chuàng)建一個(gè)新數(shù)組,新數(shù)組的結(jié)果是原數(shù)組中的每個(gè)元素都調(diào)用一次提供的函數(shù)后的返回值。
let arr = [1,2,3,4,5]; let res = arr.map(i => i * i); console.log(res) // logs [1, 4, 9, 16, 25]for...in枚舉
我是ES5版本發(fā)布的。以任意順序遍歷一個(gè)對(duì)象的除Symbol以外的可枚舉屬性。
// 遍歷對(duì)象 let profile = {name:"April",nickname:"二十七刻",country:"China"}; for(let i in profile){ let item = profile[i]; console.log(item) // 對(duì)象的鍵值 console.log(i) // 對(duì)象的鍵對(duì)應(yīng)的值 // 遍歷數(shù)組 let arr = ['a','b','c']; for(let i in arr){ let item = arr[i]; console.log(item) // 數(shù)組下標(biāo)所對(duì)應(yīng)的元素 console.log(i) // 索引,數(shù)組下標(biāo) // 遍歷字符串 let str = "abcd" for(let i in str){ let item = str[i]; console.log(item) // 字符串下標(biāo)所對(duì)應(yīng)的元素 console.log(i) // 索引 字符串的下標(biāo) }for...of迭代
我是ES6版本發(fā)布的。在可迭代對(duì)象(包括 Array,Map,Set,String,TypedArray,arguments 對(duì)象等等)上創(chuàng)建一個(gè)迭代循環(huán),調(diào)用自定義迭代鉤子,并為每個(gè)不同屬性的值執(zhí)行語句。
// 迭代數(shù)組數(shù)組 let arr = ['a','b','c']; for(let item of arr){ console.log(item) } // logs 'a' // logs 'b' // logs 'c' // 迭代字符串 let str = "abc"; for (let value of str) { console.log(value); } // logs 'a' // logs 'b' // logs 'c' // 迭代map let iterable = new Map([["a", 1], ["b", 2], ["c", 3]] for (let entry of iterable) { console.log(entry); } // logs ["a", 1] // logs ["b", 2] // logs ["c", 3] // 迭代map獲取鍵值 for (let [key, value] of iterable) { console.log(key) console.log(value); } // 迭代set let iterable = new Set([1, 1, 2, 2, 3, 3,4]); for (let value of iterable) { console.log(value); } // logs 1 // logs 2 // logs 3 // logs 4 // 迭代 DOM 節(jié)點(diǎn) let articleParagraphs = document.querySelectorAll('.article > p'); for (let paragraph of articleParagraphs) { paragraph.classList.add("paragraph"); // 給class名為“article”節(jié)點(diǎn)下的 p 標(biāo)簽添加一個(gè)名為“paragraph” class屬性。 } // 迭代arguments類數(shù)組對(duì)象 (function() { for (let argument of arguments) { console.log(argument); } })(1, 2, 3); // logs: // 1 // 2 // 3 // 迭代類型數(shù)組 let typeArr = new Uint8Array([0x00, 0xff]); for (let value of typeArr) { console.log(value); } // logs: // 0 // 255經(jīng)過第一輪的自我介紹和技能展示后,我們了解到:
for語句是最原始的循環(huán)語句。定義一個(gè)變量i(數(shù)字類型,表示數(shù)組的下標(biāo)),按照一定的條件,對(duì)i進(jìn)行循環(huán)累加。條件通常為循環(huán)對(duì)象的長(zhǎng)度,當(dāng)超過長(zhǎng)度就停止循環(huán)。因?yàn)閷?duì)象無法判斷長(zhǎng)度,所以搭配Object.keys()使用。
forEach ES5 提出。自稱是for語句的加強(qiáng)版,可以發(fā)現(xiàn)它比for語句在寫法上簡(jiǎn)單了很多。但是本質(zhì)上也是數(shù)組的循環(huán)。forEach每個(gè)數(shù)組元素執(zhí)行一次 callback 函數(shù)。也就是調(diào)用它的數(shù)組,因此,不會(huì)改變?cè)瓟?shù)組。返回值是undefine。
map ES5 提出。給原數(shù)組中的每個(gè)元素都按順序調(diào)用一次 callback 函數(shù)。生成一個(gè)新數(shù)組,不修改調(diào)用它的原數(shù)組本身。返回值是新的數(shù)組。
for...in ES5 提出。遍歷對(duì)象上的可枚舉屬性,包括原型對(duì)象上的屬性,且按任意順序進(jìn)行遍歷,也就是順序不固定。遍歷數(shù)組時(shí)把數(shù)組的下標(biāo)當(dāng)作鍵值,此時(shí)的i是個(gè)字符串型的。它是為遍歷對(duì)象屬性而構(gòu)建的,不建議與數(shù)組一起使用。
for...of ES6 提出。只遍歷可迭代對(duì)象的數(shù)據(jù)。
能力甄別
作為一個(gè)程序員,僅僅認(rèn)識(shí)他們是遠(yuǎn)遠(yuǎn)不夠的,在實(shí)際開發(fā)中鑒別他們各自的優(yōu)缺點(diǎn)。因地制宜的使用他們,揚(yáng)長(zhǎng)避短。從而提高程序的整體性能才是能力之所在。
關(guān)于跳出循環(huán)體
在循環(huán)中滿足一定條件就跳出循環(huán)體,或者跳過不符合條件的數(shù)據(jù)繼續(xù)循環(huán)其它數(shù)據(jù)。是經(jīng)常會(huì)遇到的需求。常用的語句是break 與 continue。
簡(jiǎn)單的說一下二者的區(qū)別,就當(dāng)復(fù)習(xí)好了。
break語句是跳出當(dāng)前循環(huán),并執(zhí)行當(dāng)前循環(huán)之后的語句;
continue語句是終止當(dāng)前循環(huán),并繼續(xù)執(zhí)行下一次循環(huán);
注意:forEach 與map 是不支持跳出循環(huán)體的,其它三種方法均支持。
原理 :查看forEach實(shí)現(xiàn)原理,就會(huì)理解這個(gè)問題。
Array.prototype.forEach(callbackfn [,thisArg]{ }傳入的function是這里的回調(diào)函數(shù)。在回調(diào)函數(shù)里面使用break肯定是非法的,因?yàn)閎reak只能用于跳出循環(huán),回調(diào)函數(shù)不是循環(huán)體。
在回調(diào)函數(shù)中使用return,只是將結(jié)果返回到上級(jí)函數(shù),也就是這個(gè)for循環(huán)中,并沒有結(jié)束for循環(huán),所以return也是無效的。
map() 同理。
map()鏈?zhǔn)秸{(diào)用
map() 方法是可以鏈?zhǔn)秸{(diào)用的,這意味著它可以方便的結(jié)合其它方法一起使用。例如:reduce(), sort(), filter() 等。但是其它方法并不能做到這一點(diǎn)。forEach()的返回值是undefined,所以無法鏈?zhǔn)秸{(diào)用。
// 將元素乘以本身,再進(jìn)行求和。 let arr = [1, 2, 3, 4, 5]; let res1 = arr.map(item => item * item).reduce((total, value) => total + value); console.log(res1) // logs 55 undefined"for...in會(huì)遍歷出原型對(duì)象上的屬性
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; var arr = ['a', 'b', 'c']; arr.foo = 'hello for (var i in arr) { console.log(i); } // logs // 0 // 1 // 2 // foo // arrCustom // objCustom然而在實(shí)際的開發(fā)中,我們并不需要原型對(duì)象上的屬性。這種情況下我們可以使用hasOwnProperty() 方法,它會(huì)返回一個(gè)布爾值,指示對(duì)象自身屬性中是否具有指定的屬性(也就是,是否有指定的鍵)。如下:
Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; var arr = ['a', 'b', 'c']; arr.foo = 'hello for (var i in arr) { if (arr.hasOwnProperty(i)) { console.log(i); } } // logs // 0 // 1 // 2 // foo // 可見數(shù)組本身的屬性還是無法擺脫。此時(shí)建議使用 forEach對(duì)于純對(duì)象的遍歷,選擇for..in枚舉更方便;對(duì)于數(shù)組遍歷,如果不需要知道索引for..of迭代更合適,因?yàn)檫€可以中斷;如果需要知道索引,則forEach()更合適;對(duì)于其他字符串,類數(shù)組,類型數(shù)組的迭代,for..of更占上風(fēng)更勝一籌。但是注意低版本瀏覽器的是配性。
性能
有興趣的讀者可以找一組數(shù)據(jù)自行測(cè)試,文章就直接給出結(jié)果了,并做相應(yīng)的解釋。
for > for-of > forEach > map > for-in
for 循環(huán)當(dāng)然是最簡(jiǎn)單的,因?yàn)樗鼪]有任何額外的函數(shù)調(diào)用棧和上下文;
for...of只要具有Iterator接口的數(shù)據(jù)結(jié)構(gòu),都可以使用它迭代成員。它直接讀取的是鍵值。
forEach,因?yàn)樗鋵?shí)比我們想象得要復(fù)雜一些,它實(shí)際上是array.forEach(function(currentValue, index, arr), thisValue)它不是普通的 for 循環(huán)的語法糖,還有諸多參數(shù)和上下文需要在執(zhí)行的時(shí)候考慮進(jìn)來,這里可能拖慢性能;
map() 最慢,因?yàn)樗姆祷刂凳且粋€(gè)等長(zhǎng)的全新的數(shù)組,數(shù)組創(chuàng)建和賦值產(chǎn)生的性能開銷很大。
for...in需要窮舉對(duì)象的所有屬性,包括自定義的添加的屬性也能遍歷到。且for...in的key是String類型,有轉(zhuǎn)換過程,開銷比較大。
總結(jié)
在實(shí)際開發(fā)中我們要結(jié)合語義話、可讀性和程序性能,去選擇究竟使用哪種方案。
如果你需要將數(shù)組按照某種規(guī)則映射為另一個(gè)數(shù)組,就應(yīng)該用 map。
如果你需要進(jìn)行簡(jiǎn)單的遍歷,用 forEach 或者 for of。
如果你需要對(duì)迭代器進(jìn)行遍歷,用 for of。
如果你需要過濾出符合條件的項(xiàng),用 filterr。
如果你需要先按照規(guī)則映射為新數(shù)組,再根據(jù)條件過濾,那就用一個(gè) map 加一個(gè) filter。
文章標(biāo)題:使用for循環(huán)遍歷的優(yōu)勢(shì)
本文網(wǎng)址:http://weahome.cn/article/josehs.html