尴尬,通篇使用 if

以给博客园头部导航条链接添加图标为例, 接下来看看如何分别使用对象、数组、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的效率没有带索引的遍历方式高,当你需要遍历大量数据时,最好换用其它方式遍历数据。如有错误,欢迎指正!

posted @ 2020-04-06 19:18  DIVMonster  阅读(...)  评论(...编辑  收藏