尴尬,通篇使用 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
的效率没有带索引的遍历方式高,当你需要遍历大量数据时,最好换用其它方式遍历数据。如有错误,欢迎指正!