這是第 100 篇不摻水的原創,想獲取更多原創好文,請搜索公衆號關注咱們吧~ 本文首發於政採雲前端博客: JS經常使用的循環遍歷你會幾種
數組和對象做爲一個最基礎數據結構,在各類編程語言中都充當着相當重要的角色,你很難想象沒有數組和對象的編程語言會是什麼模樣,特別是 JS ,弱類型語言,很是靈活。本文帶你瞭解經常使用數組遍歷、對象遍歷的使用對比以及注意事項。javascript
隨着 JS 的不斷髮展,截至 ES7 規範已經有十多種遍歷方法。下面按照功能相似的方法爲一組,來介紹數組的經常使用遍歷方法。前端
const list = [1, 2, 3, 4, 5, 6, 7, 8,, 10, 11]; 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 === 5) return; console.log(index); // 0 1 2 3 5 6 7 9 10 console.log(item); // 1 2 3 4 6 7 8 10 11 });
小結java
const list = [ { name: '頭部導航', backward: false }, { name: '輪播', backward: true }, { name: '頁腳', backward: false }, ]; const someBackward = list.some(item => item.backward); // someBackward: true const everyNewest = list.every(item => !item.backward); // everyNewest: false
小結編程
const list = [ { name: '頭部導航', type: 'nav', id: 1 },, { name: '輪播', type: 'content', id: 2 }, { name: '頁腳', type: 'nav', id: 3 }, ]; 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 }, // ]
小結數組
const list = [ { name: '頭部導航', id: 1 }, { name: '輪播', id: 2 }, { name: '頁腳', id: 3 }, ]; const result = list.find((item) => item.id === 3); // result: { name: '頁腳', id: 3 } result.name = '底部導航'; // list: [ // { name: '頭部導航', id: 1 }, // { name: '輪播', id: 2 }, // { name: '底部導航', id: 3 }, // ] const index = list.findIndex((item) => item.id === 3); // index: 2 list[index].name // '底部導航';
小結瀏覽器
reduce 方法接收兩個參數,第一個參數是回調函數(callback) ,第二個參數是初始值(initialValue)。緩存
reduceRight 方法除了與reduce執行方向相反外(從右往左),其餘徹底與其一致。微信
回調函數接收四個參數:數據結構
若是不傳入初始值,reduce 方法會從索引 1 開始執行回調函數,若是傳入初始值,將從索引 0 開始、並從初始值的基礎上累計執行回調。
const list = [ { name: 'left', width: 20 }, { name: 'center', width: 70 }, { name: 'right', width: 10 }, ]; const total = list.reduce((currentTotal, item) => { return currentTotal + item.width; }, 0); // total: 100
const list = [ { name: 'left', width: 20 }, { name: 'right', width: 10 }, { name: 'center', width: 70 }, { name: 'right', width: 10 }, { name: 'left', width: 20 }, { name: 'right', width: 10 }, ]; 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 }, // ]
const list = [ { name: 'left', width: 20 }, { name: 'right', width: 30 }, { name: 'center', width: 70 }, { name: 'top', width: 40 }, { name: 'bottom', width: 20 }, ]; 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個你不得不知道的數組reduce高級用法》編程語言
說了這麼多,那這些遍歷方法, 在性能上有什麼差別呢?咱們在 Chrome 瀏覽器中嘗試。我採用每一個循環執行10次,去除最大、最小值 取平均數,下降偏差。
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
從打印結果能夠看出,for 循環的速度最快,for of 循環最慢
是否可終止 | ||||
---|---|---|---|---|
** | break | continue | return | 性能(ms) |
for | 終止 ✅ | 跳出本次循環 ✅ | ❌ | 2.42 |
forEach | ❌ | ❌ | ❌ | 3.12 |
map | ❌ | ❌ | ❌ | 3.74 |
for of | 終止 ✅ | 跳出本次循環 ✅ | ❌ | 6.33 |
some | ❌ | ❌ | return true ✅ | 2.78 |
every | ❌ | ❌ | return false ✅ | 2.75 |
最後,不一樣瀏覽器內核 也會有些差別,有興趣的同窗也能夠嘗試一下。
在對象遍歷中,常常須要遍歷對象的鍵、值,ES5 提供了 for...in 用來遍歷對象,然而其涉及對象屬性的「可枚舉屬性」、原型鏈屬性等,下面將從 Object 對象本質探尋各類遍歷對象的方法,並區分經常使用方法的一些特色。
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 過濾
小結
使用 for in 循環時,返回的是全部可以經過對象訪問的、可枚舉的屬性,既包括存在於實例中的屬性,也包括存在於原型中的實例。若是隻須要獲取對象的實例屬性,可使用 hasOwnProperty 進行過濾。
使用時,要使用(const x in a)
而不是(x in a)
後者將會建立一個全局變量。
for in 的循環順序,參考【JavaScript 權威指南】(第七版)6.6.1。
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']
小結
用於獲取對象自身全部的可枚舉的屬性值,但不包括原型中的屬性,而後返回一個由屬性名組成的數組。
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']
小結
用於獲取對象自身全部的可枚舉的屬性值,但不包括原型中的屬性,而後返回一個由屬性值組成的數組。
const str = 'ab';for (const [key, value] of Object.entries(str)) { console.log(`${key}: ${value}`);}// 0: a// 1: bconst arr = ['a', 'b'];for (const [key, value] of Object.entries(arr)) { console.log(`${key}: ${value}`);}// 0: a// 1: bconst obj = { 1: 'b', 0: 'a' };for (const [key, value] of Object.entries(obj)) { console.log(`${key}: ${value}`);}// 0: a// 1: b
小結
用於獲取對象自身全部的可枚舉的屬性值,但不包括原型中的屬性,而後返回二維數組。每個子數組由對象的屬性名、屬性值組成。能夠同時拿到屬性名與屬性值的方法。
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']
小結
用於獲取對象自身全部的可枚舉的屬性值,但不包括原型中的屬性,而後返回一個由屬性名組成的數組。
咱們對比了多種經常使用遍歷的方法的差別,在瞭解了這些以後,咱們在使用的時候須要好好思考一下,就能知道那個方法是最合適的。歡迎你們糾正補充。
開源地址 www.zoo.team/openweekly/ (小報官網首頁有微信交流羣)
政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 40 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com