以給博客園頭部導航條鏈接添加圖標為例, 接下來看看如何分別使用對象、數組、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
的效率沒有帶索引的遍歷方式高,當你需要遍歷大量數據時,最好換用其它方式遍歷數據。如有錯誤,歡迎指正!