1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        如果再寫(xiě)for循環(huán),我就。。。

        共 5768字,需瀏覽 12分鐘

         ·

        2022-03-16 02:42


        點(diǎn)擊上方[全棧開(kāi)發(fā)者社區(qū)]右上角[...][設(shè)為星標(biāo)?

        點(diǎn)擊領(lǐng)取全棧資料全棧資料

        幾種遍歷方法中for執(zhí)行最快,它沒(méi)有任何額外的函數(shù)調(diào)用棧和上下文。但在實(shí)際開(kāi)發(fā)中我們要結(jié)合語(yǔ)義話、可讀性和程序性能,去選擇究竟使用哪種方案。下面來(lái)看for?,?foreach?,?map?,for...in?,?for...of五種方法現(xiàn)場(chǎng)battle。

        自我介紹

        for
        我是最早出現(xiàn)的一方遍歷語(yǔ)句,在座的各位需稱(chēng)我一聲爺爺。我能滿足開(kāi)發(fā)人員的絕大多數(shù)的需求。

        // 遍歷數(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;i????articleParagraphs[i].classList.add("paragraph");
        ????// 給class名為“article”節(jié)點(diǎn)下的 p 標(biāo)簽添加一個(gè)名為“paragraph” class屬性。
        }


        forEach


        我是ES5版本發(fā)布的。按升序?yàn)閿?shù)組中含有效值的每一項(xiàng)執(zhí)行一次 callback 函數(shù),那些已刪除或者未初始化的項(xiàng)將被跳過(guò)(例如在稀疏數(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í)行語(yǔ)句。

        // 迭代數(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類(lèi)數(shù)組對(duì)象
        (function()?{
        ??for?(let?argument?of?arguments) {
        ????console.log(argument);
        ??}
        })(1,?2,?3);
        // logs:
        // 1
        // 2
        // 3


        // 迭代類(lèi)型數(shù)組
        let?typeArr =?new?Uint8Array([0x00,?0xff]);
        for?(let?value?of?typeArr) {
        ??console.log(value);
        }
        // logs:
        // 0
        // 255

        經(jīng)過(guò)第一輪的自我介紹和技能展示后,我們了解到:
        • for語(yǔ)句是最原始的循環(huán)語(yǔ)句。定義一個(gè)變量i(數(shù)字類(lèi)型,表示數(shù)組的下標(biāo)),按照一定的條件,對(duì)i進(jìn)行循環(huán)累加。條件通常為循環(huán)對(duì)象的長(zhǎng)度,當(dāng)超過(guò)長(zhǎng)度就停止循環(huán)。因?yàn)閷?duì)象無(wú)法判斷長(zhǎng)度,所以搭配Object.keys()使用。
        • forEach?ES5 提出。自稱(chēng)是for語(yǔ)句的加強(qiáng)版,可以發(fā)現(xiàn)它比for語(yǔ)句在寫(xiě)法上簡(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í)際開(kāi)發(fā)中鑒別他們各自的優(yōu)缺點(diǎn)。因地制宜的使用他們,揚(yáng)長(zhǎng)避短。從而提高程序的整體性能才是能力之所在。

        關(guān)于跳出循環(huán)體

        在循環(huán)中滿足一定條件就跳出循環(huán)體,或者跳過(guò)不符合條件的數(shù)據(jù)繼續(xù)循環(huán)其它數(shù)據(jù)。是經(jīng)常會(huì)遇到的需求。常用的語(yǔ)句是break?與?continue。
        簡(jiǎn)單的說(shuō)一下二者的區(qū)別,就當(dāng)復(fù)習(xí)好了。
        • break語(yǔ)句是跳出當(dāng)前循環(huán),并執(zhí)行當(dāng)前循環(huán)之后的語(yǔ)句;
        • continue語(yǔ)句是終止當(dāng)前循環(huán),并繼續(xù)執(zhí)行下一次循環(huán);
        注意forEach?與map?是不支持跳出循環(huán)體的,其它三種方法均支持。
        原理?:查看forEach實(shí)現(xiàn)原理,就會(huì)理解這個(gè)問(wèn)題。

        Array.prototype.forEachcallbackfn?[,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)中,并沒(méi)有結(jié)束for循環(huán),所以return也是無(wú)效的。
        map()?同理。

        map()鏈?zhǔn)秸{(diào)用

        map()?方法是可以鏈?zhǔn)秸{(diào)用的,這意味著它可以方便的結(jié)合其它方法一起使用。例如:reduce(),?sort(),?filter()?等。但是其它方法并不能做到這一點(diǎn)。forEach()的返回值是undefined,所以無(wú)法鏈?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í)際的開(kāi)發(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

        // 可見(jiàn)數(shù)組本身的屬性還是無(wú)法擺脫。此時(shí)建議使用 forEach

        對(duì)于純對(duì)象的遍歷,選擇for..in枚舉更方便;對(duì)于數(shù)組遍歷,如果不需要知道索引for..of迭代更合適,因?yàn)檫€可以中斷;如果需要知道索引,則forEach()更合適;對(duì)于其他字符串,類(lèi)數(shù)組,類(lèi)型數(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)樗鼪](méi)有任何額外的函數(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)的語(yǔ)法糖,還有諸多參數(shù)和上下文需要在執(zhí)行的時(shí)候考慮進(jìn)來(lái),這里可能拖慢性能;
        • map()?最慢,因?yàn)樗姆祷刂凳且粋€(gè)等長(zhǎng)的全新的數(shù)組,數(shù)組創(chuàng)建和賦值產(chǎn)生的性能開(kāi)銷(xiāo)很大。
        • for...in需要窮舉對(duì)象的所有屬性,包括自定義的添加的屬性也能遍歷到。且for...in的key是String類(lèi)型,有轉(zhuǎn)換過(guò)程,開(kāi)銷(xiāo)比較大。

        總結(jié)

        在實(shí)際開(kāi)發(fā)中我們要結(jié)合語(yǔ)義話、可讀性和程序性能,去選擇究竟使用哪種方案。
        如果你需要將數(shù)組按照某種規(guī)則映射為另一個(gè)數(shù)組,就應(yīng)該用 map。
        如果你需要進(jìn)行簡(jiǎn)單的遍歷,用 forEach 或者 for of。
        如果你需要對(duì)迭代器進(jìn)行遍歷,用 for of。
        如果你需要過(guò)濾出符合條件的項(xiàng),用 filterr。
        如果你需要先按照規(guī)則映射為新數(shù)組,再根據(jù)條件過(guò)濾,那就用一個(gè) map 加一個(gè) filter。
        總之,因地制宜,因時(shí)而變。千萬(wàn)不要因?yàn)檫^(guò)分追求性能,而忽略了語(yǔ)義和可讀性。在您的統(tǒng)治之下,他們5個(gè)只能是各自發(fā)揮長(zhǎng)處,誰(shuí)都別想稱(chēng)霸。

        覺(jué)得本文對(duì)你有幫助?請(qǐng)分享給更多人

        關(guān)注「全棧開(kāi)發(fā)者社區(qū)」加星標(biāo),提升全棧技能

        本公眾號(hào)會(huì)不定期給大家發(fā)福利,包括送書(shū)、學(xué)習(xí)資源等,敬請(qǐng)期待吧!

        如果感覺(jué)推送內(nèi)容不錯(cuò),不妨右下角點(diǎn)個(gè)在看轉(zhuǎn)發(fā)朋友圈或收藏,感謝支持。

        好文章,留言、點(diǎn)贊、在看和分享一條龍

        瀏覽 81
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            黑人插逼视频 | 国产婷婷色一区二区在线观看 | 日韩伦理电影院 | 欧美日韩操逼网 | 放荡的少妇2欧美版 | 五月天性爱网站 | 宝贝乖~张开腿我轻点 | 大巴车男人狂躁女人小说 | 韩国成人网站www永久 | 少妇一级1淫片 |