<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【JavaScript】JS常用的循環(huán)遍歷你會幾種?

          共 11906字,需瀏覽 24分鐘

           ·

          2021-06-22 08:11


          本文首發(fā)于政采云前端團隊博客:JS常用的循環(huán)遍歷你會幾種

          https://www.zoo.team/article/cycle-in-js

          前言

          數(shù)組和對象作為一個最基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),在各種編程語言中都充當著至關(guān)重要的角色,你很難想象沒有數(shù)組和對象的編程語言會是什么模樣。特別是 JS,弱類型語言,非常靈活。本文帶你了解常用數(shù)組遍歷、對象遍歷的使用,對比以及注意事項。

          數(shù)組遍歷

          隨著 JS 的不斷發(fā)展,截至 ES7 規(guī)范已經(jīng)有十多種遍歷方法。下面按照功能類似的方法為一組,來介紹數(shù)組的常用遍歷方法。

          for、forEach、for ...of

          const list = [12345678,, 1011];

          for (let i = 0, len = list.length; i < len; i++) {
            if (list[i] === 5) {
              break// 1 2 3 4
              // continue; // 1 2 3 4 6 7 8 undefined 10 11
            }
            console.log(list[i]);
          }

          for (const item of list) {
            if (item === 5) {
              break// 1 2 3 4
              // continue; // 1 2 3 4 6 7 8 undefined 10 11
            }
            console.log(item);
          }

          list.forEach((item, index, arr) => {
            if (item === 5return;
            console.log(index); // 0 1 2 3 5 6 7 9 10
            console.log(item); // 1 2 3 4 6 7 8 9 10
          });

          小結(jié)

          • 三者都是基本的由左到右遍歷數(shù)組。
          • forEach 無法跳出循環(huán),for 和 for ...of 可以使用 break 或者 continue 跳過或中斷。
          • for ...of 直接訪問的是實際元素,for 遍歷數(shù)組索引,forEach 回調(diào)函數(shù)參數(shù)更豐富,元素、索引、原數(shù)組都可以獲取。
          • for ...of 與 for 如果數(shù)組中存在空元素,同樣會執(zhí)行。

          some、every

          const list = [
            { name'頭部導航'backwardfalse },
            { name'輪播'backwardtrue },
            { name'頁腳'backwardfalse },
          ];
          const someBackward = list.some(item => item.backward);
          // someBackward: true
          const everyNewest = list.every(item => !item.backward);
          // everyNewest: false

          小結(jié)

          • 二者都是用來做數(shù)組條件判斷的,都是返回一個布爾值。
          • 二者都可以被中斷。
          • some 若某一元素滿足條件,返回 true,循環(huán)中斷。所有元素不滿足條件,返回 false。
          • every 與 some 相反,若有一元素不滿足條件,返回 false,循環(huán)中斷。所有元素滿足條件,返回 true。

          filter、map

          const list = [
          name'頭部導航'type'nav'id1 },,
          name'輪播'type'content'id2 },
          name'頁腳'type'nav'id3 },
          ];
          const resultList = list.filter(item => {
            console.log(item);
            return item.type === 'nav';
          });
          // resultList: [
          //   { name: '頭部導航', type: 'nav', id: 1 },
          //   { name: '頁腳', type: 'nav', id: 3 },
          // ]

          const newList = list.map(item => {
            console.log(item);
            return item.id;
          });
          // newList: [1, empty, 2, 3]

          // list: [
          //   { name: '頭部導航', type: 'nav', id: 1 },
          //   empty,
          //   { name: '輪播', type: 'content', id: 2 },
          //   { name: '頁腳', type: 'nav', id: 3 },
          // ]

          小結(jié)

          • 二者都是生成一個新數(shù)組,都不會改變原數(shù)組(不包括遍歷對象數(shù)組時,在回調(diào)函數(shù)中操作元素對象)。
          • 二者都會跳過空元素。有興趣的同學可以自己打印一下。
          • map 會將回調(diào)函數(shù)的返回值組成一個新數(shù)組,數(shù)組長度與原數(shù)組一致。
          • filter 會將符合回調(diào)函數(shù)條件的元素組成一個新數(shù)組。
          • map 生成的新數(shù)組元素可自定義。
          • filter 生成的新數(shù)組元素不可自定義,與對應(yīng)原數(shù)組元素一致。

          find、findIndex

          const list = [
              { name'頭部導航'id1 },
              { name'輪播'id2 },
              { name'頁腳'id3 },
          ];
          const result = list.find(item => item.id === 3);
          // result: { name: '頁腳', id: 3 }
          const index = list.findIndex(item => item.id === 3);
          // index: 2

          小結(jié)

          • 二者都是用來查找數(shù)組元素。
          • find 方法返回數(shù)組中滿足 callback 函數(shù)的第一個元素的值。如果不存在返回 undefined。
          • findIndex 它返回數(shù)組中找到的元素的索引,而不是其值,如果不存在返回 -1。

          reduce、reduceRight

          reduce 方法接收兩個參數(shù),第一個參數(shù)是回調(diào)函數(shù)(callback) ,第二個參數(shù)是初始值(initialValue)。

          reduceRight 方法除了與 reduce 執(zhí)行方向相反外(從右往左),其他完全與其一致。

          回調(diào)函數(shù)接收四個參數(shù):

          • accumulator:MDN 上解釋為累計器,但我覺得不恰當,按我的理解它應(yīng)該是截至當前元素,之前所有的數(shù)組元素被回調(diào)函數(shù)處理累計的結(jié)果。
          • current:當前被執(zhí)行的數(shù)組元素。
          • currentIndex: 當前被執(zhí)行的數(shù)組元素索引。
          • sourceArray:原數(shù)組,也就是調(diào)用 reduce 方法的數(shù)組。
           

          如果不傳入初始值,reduce 方法會從索引 1 開始執(zhí)行回調(diào)函數(shù),如果傳入初始值,將從索引 0 開始、并從初始值的基礎(chǔ)上累計執(zhí)行回調(diào)。

          計算對象數(shù)組某一屬性的總和
          const list  = [
            { name'left'width20 },
            { name'center'width70 },
            { name'right'width10 },
          ];
          const total = list.reduce((currentTotal, item) => {
            return currentTotal + item.width;
          }, 0);
          // total: 100
          對象數(shù)組的去重,并統(tǒng)計每一項重復次數(shù)
          const list  = [
            { name'left'width20 },
            { name'right'width10 },
            { name'center'width70 },
            { name'right'width10 },
            { name'left'width20 },
            { name'right'width10 },
          ];
          const repeatTime = {};
          const result = list.reduce((array, item) => {
            if (repeatTime[item.name]) {
              repeatTime[item.name]++;
              return array;
            }
            repeatTime[item.name] = 1;
            return [...array, item];
          }, []);
          // repeatTime: { left: 2, right: 3, center: 1 }
          // result: [
          //   { name: 'left', width: 20 },
          //   { name: 'right', width: 10 },
          //   { name: 'center', width: 70 },
          // ]
          對象數(shù)組最大/最小值獲取
          const list  = [
            { name'left'width20 },
            { name'right'width30 },
            { name'center'width70 },
            { name'top'width40 },
            { name'bottom'width20 },
          ];
          const max = list.reduce((curItem, item) => {
            return curItem.width >= item.width ? curItem : item;
          });
          const min = list.reduce((curItem, item) => {
            return curItem.width <= item.width ? curItem : item;
          });
          // max: { name: "center", width: 70 }
          // min: { name: "left", width: 20 }

          reduce 很強大,更多奇技淫巧推薦查看這篇《25個你不得不知道的數(shù)組reduce高級用法》(https://juejin.im/post/6844904063729926152)

          性能對比

          說了這么多,那這些遍歷方法, 在性能上有什么差異呢?我們在 Chrome 瀏覽器中嘗試。我采用每個循環(huán)執(zhí)行 10 次,去除最大、最小值 取平均數(shù),降低誤差。

          var list = Array(100000).fill(1)

          console.time('for');
          for (let index = 0, len = list.length; index < len; index++) {
          }
          console.timeEnd('for');
          // for: 2.427642822265625 ms

          console.time('every');
          list.every(() => { return true })
          console.timeEnd('every')
          // some: 2.751708984375 ms

          console.time('some');
          list.some(() => { return false })
          console.timeEnd('some')
          // some: 2.786590576171875 ms

          console.time('foreach');
          list.forEach(() => {})
          console.timeEnd('foreach');
          // foreach: 3.126708984375 ms

          console.time('map');
          list.map(() => {})
          console.timeEnd('map');
          // map: 3.743743896484375 ms

          console.time('forof');
          for (let index of list) {
          }
          console.timeEnd('forof')
          // forof: 6.33380126953125 ms

          從打印結(jié)果可以看出,for 循環(huán)的速度最快,for ...of 循環(huán)最慢。

          常用遍歷的終止、性能表格對比


          是否可終止


          ****breakcontinuereturn性能(ms)
          for終止 ?跳出本次循環(huán) ??2.42
          forEach???3.12
          map???3.74
          for of終止 ?跳出本次循環(huán) ??6.33
          some??return true ?2.78
          every??return false ?2.75

          最后,不同瀏覽器內(nèi)核 也會有些差異,有興趣的同學也可以嘗試一下。

          對象遍歷

          在對象遍歷中,經(jīng)常需要遍歷對象的鍵、值,ES5 提供了 for...in 用來遍歷對象,然而其涉及對象屬性的“可枚舉屬性”、原型鏈屬性等,下面將從 Object 對象本質(zhì)探尋各種遍歷對象的方法,并區(qū)分常用方法的一些特點。

          for in

          Object.prototype.fun = () => {};
          const obj = { 2'a'1'b' };
          for (const i in obj) {
            console.log(i, ':', obj[i]);
          }
          // 1: b
          // 2: a
          // fun : () => {} Object 原型鏈上擴展的方法也被遍歷出來
          for (const i in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, i)) {
                console.log(i, ':', obj[i]);
              }
          }
          // name : a 不屬于自身的屬性將被 hasOwnProperty 過濾

          小結(jié)

          使用 for in 循環(huán)時,返回的是所有能夠通過對象訪問的、可枚舉的屬性,既包括存在于實例中的屬性,也包括存在于原型中的實例。如果只需要獲取對象的實例屬性,可以使用 hasOwnProperty 進行過濾。

          使用時,要使用 (const x in a) 不是 (x in a) 者將會創(chuàng)建一個全局變量。

          for in 的循環(huán)順序,參考【 JavaScript 權(quán)威指南】(第七版)6.6.1。

          • 先列出名字為非負整數(shù)的字符串屬性,按照數(shù)值順序從最小到最大。這條規(guī)則意味著數(shù)組和類數(shù)組對象的屬性會按照順序被枚舉。
          • 在列出類數(shù)組索引的所有屬性之后,在列出所有剩下的字符串名字(包括看起來像整負數(shù)或浮點數(shù)的名字)的屬性。這些屬性按照它們添加到對象的先后順序列出。對于在對象字面量中定義的屬性,按照他們在字面量中出現(xiàn)的順序列出。
          • 最后,名字為符號對象的屬性按照它們添加到對象的先后順序列出。

          Object.keys

          Object.prototype.fun = () => {};
          const str = 'ab';
          console.log(Object.keys(str));
          // ['0', '1']
          const arr = ['a''b'];
          console.log(Object.keys(arr));
          // ['0', '1']
          const obj = { 1'b'0'a' };
          console.log(Object.keys(obj));
          // ['0', '1']

          小結(jié)

          用于獲取對象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個由屬性名組成的數(shù)組。

          Object.values

          Object.prototype.fun = () => {};
          const str = 'ab';
          console.log(Object.values(str));
          // ['a', 'b']
          const arr = ['a''b'];
          console.log(Object.values(arr));
          // ['a', 'b']
          const obj = { 1'b'0'a' };
          console.log(Object.values(obj));
          // ['a', 'b']

          小結(jié)

          用于獲取對象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個由屬性值組成的數(shù)組。

          Object.entries

          const str = 'ab';
          for (const [key, value] of Object.entries(str)) {
              console.log(`${key}${value}`);
          }
          // 0: a
          // 1: b
          const arr = ['a''b'];
          for (const [key, value] of Object.entries(arr)) {
              console.log(`${key}${value}`);
          }
          // 0: a
          // 1: b
          const obj = { 1'b'0'a' };
          for (const [key, value] of Object.entries(obj)) {
              console.log(`${key}${value}`);
          }
          // 0: a
          // 1: b

          小結(jié)

          用于獲取對象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回二維數(shù)組。每一個子數(shù)組由對象的屬性名、屬性值組成??梢酝瑫r拿到屬性名與屬性值的方法。

          Object.getOwnPropertyNames

          Object.prototype.fun = () => {};
          Array.prototype.fun = () => {};
          const str = 'ab';
          console.log(Object.getOwnPropertyNames(str));
          // ['0', '1', 'length']
          const arr = ['a''b'];
          console.log(Object.getOwnPropertyNames(arr));
          // ['0', '1', 'length']
          const obj = { 1'b'0'a' };
          console.log(Object.getOwnPropertyNames(obj));
          // ['0', '1']

          小結(jié)

          用于獲取對象自身所有的可枚舉的屬性值,但不包括原型中的屬性,然后返回一個由屬性名組成的數(shù)組。

          總結(jié)

          我們對比了多種常用遍歷的方法的差異,在了解了這些之后,我們在使用的時候需要好好思考一下,就能知道那個方法是最合適的。歡迎大家糾正補充。

          瀏覽 28
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久免费精品视频观看 | 精品久久久无码中文字幕 | 天堂中文网在线 | 色色色综合色 | 欧美性爱区第一页 |