尷尬,通篇使用 if
- 2020 年 4 月 6 日
- 筆記
以給部落格園頭部導航條鏈接添加圖標為例, 接下來看看如何分別使用對象、數組、Map 優化它的。
前置
1.接下來給頭部導航條添的圖標包含:
- 部落格園首頁
- 新隨筆
- 部落格首頁
- 聯繫
- 訂閱
- 管理
2.這裡封裝了一個返回 svg 的 function, 下文的 iconInSvg(icon)
即是調用了這個方法。
function iconInSvg(icon) { return ` <svg class="icon" aria-hidden="true"> <use xlink:href="${icon}"></use> </svg> ` }
用if羅列
部落格園可以在 管理 -> 選項 介面禁用一些鏈接, 所以在添加 svg 圖標之前需要判斷鏈接是否存在。
import { cnblog, home, pens, contact, rss, admin } from '../constants/icons' import { iconInSvg } from '@tools' function setNavIcons() { // 部落格園首頁 if ($('#blog_nav_sitehome').length !== 0) { $('#blog_nav_sitehome').prepend(iconInSvg(cnblog)) } // 部落格首頁 if ($('#blog_nav_myhome').length !== 0) { $('#blog_nav_myhome').prepend(iconInSvg(home)) } // 新隨筆 if ($('#blog_nav_newpost').length !== 0) { $('#blog_nav_newpost').prepend(iconInSvg(pens)) } // 聯繫 if ($('#blog_nav_contact').length !== 0) { $('#blog_nav_contact').prepend(iconInSvg(contact)) } // 訂閱 if ($('#blog_nav_rss').length !== 0) { $('#blog_nav_rss').prepend(iconInSvg(rss)) } // 管理 if ($('#blog_nav_admin').length !== 0) { $('#blog_nav_admin').prepend(iconInSvg(admin)) } } export default setNavIcons
可以發現程式碼有大量重複,思考如何優化程式碼。將選擇器和圖標抽離,以 key value 的形式一一對應,然後進行遍歷,執行相同的邏輯:先判斷再插入圖標。
使用對象
const items = { '#blog_nav_sitehome': cnblog, '#blog_nav_myhome': home, '#blog_nav_newpost': pens, '#blog_nav_contact': contact, '#blog_nav_rss': rss, '#blog_nav_admin': admin, } for (let selector in items) { if ($(selector).length !== 0) { $(selector).prepend(iconInSvg(items[selector])) } }
- js的對象本質上是鍵值對的集合(Hash結構),如果給對象設置為一個不為字元串的 key,會自動轉為字元串
- 這裡直接設置 key 為字元串,需要使用
[]
來取其值
使用數組
針對給頭部導航條添加圖標的場景,使用對象重寫這段程式碼應該是最方便的解法了。接下來使用數組對象的形式將它重寫,並進行對比。
const items = [ { selector: '#blog_nav_sitehome', icon: cnblog }, { selector: '#blog_nav_myhome', icon: home }, { selector: '#blog_nav_newpost', icon: pens }, { selector: '#blog_nav_contact', icon: contact }, { selector: '#blog_nav_rss', icon: rss }, { selector: '#blog_nav_admin', icon: admin }, ] for (let { selector, icon } of items) { if ($(selector).length !== 0) { $(selector).prepend(iconInSvg(icon)) } }
- 數組對象的形式描述的更加清晰
- 在這種數據結構下,通過結構賦值能夠快速取到值
- 循環體內的程式碼更易讀
相比後面的 Map 數據結構,在這個場景下我更喜歡用數組對象的形式。
試試 Map
由於 js 對象的 key 本質上只能使用字元串,這就帶來一定的局限性。Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。「鍵」的範圍不限於字元串,各種類型的值(包括對象)都可以當作鍵。接下來使用 Map 重寫這段程式碼。
const items = new Map([ ['#blog_nav_sitehome', cnblog], ['#blog_nav_myhome', home], ['#blog_nav_newpost', pens], ['#blog_nav_contact', contact], ['#blog_nav_rss', rss], ['#blog_nav_admin', admin], ]) for (let [selector, icon] of items.entries()) { if ($(selector).length !== 0) { $(selector).prepend(iconInSvg(icon)) } }
這個小項目雖然使用了 babel 來處理 es6,但 Map 無法像class那樣被轉化,class 是語法糖。Map 真是個好東西,如果你不需要兼容IE9以下的話。
總結
各有好處。需要注意的是,for of
的效率沒有帶索引的遍歷方式高,當你需要遍歷大量數據時,最好換用其它方式遍曆數據。如有錯誤,歡迎指正!