你有没有见过这样的代码
1 | if (type !== 'default') { |
这样的代码
1 | if (nodeList[i].className === 'topLeft') { |
这样的代码
1 | if ( param === 1 || param === 2 || param === 3 || param === 'a' || param === 'b' ) {} |
我们在编写 js 代码的时候, 可能在很多时候就是写出来的代码, 实现了他的功能然后测一下没问题之后就没有然后了, 但是有时候我们是可以对代码本身做一些优化的,这可能是很小的一些问题, 但是也是很容易被忽略的一些问题。
比如时常会遇到一些比如判断啊或者其他的什么的, 在语句逐渐变得多了之后, 代码没处理好可能就会比较臃肿, 然后一时又想不到该怎么去优化,在此提供一些可参考的代码示例
条件判断
if-else
多数的嵌套判断, 都是可以被简化的
1 | if (!isEdit) { |
用三元运算符代替简单的, 虽然这个大家都知道, 但是代码中还是很多这种代码, 可以稍微注意一下
1 | if (type !== 'default') { |
多个 if… else if…
我们在写 js 的时候时长会遇到复杂逻辑判断的情况, 通常大家都会用 if … else if 或者 switch 来实现多个条件的判断, 但是这时就有一个问题, 随着条件越来越多,代码中的 if else/switch 会越来越臃肿, 虽然不会说看不懂, 但是在某些情况下看着就没有那么直观, 比如以下这种
1 | if (nodeList[i].className === 'topLeft') { |
在上边这段代码中, 很多 else if, 根据不同的 class 名称, 传不同参数调用同一个方法
改成 switch, 看起来并没有好很多
1 | switch (nodeList[i].className) { |
利用 Object
将判断条件作为对象的属性名,将处理逻辑作为对象的属性值,在按钮点击的时候,通过对象属性查找的方式来进行逻辑判断。
1 | const classNames = { |
以下是vue源码中存在的这样的代码片段, 先定义了两个对象, 最后再从这里边去获取相应的值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44const keyCodes: { [key: string]: number | Array<number> } = {
esc: 27,
tab: 9,
enter: 13,
space: 32,
up: 38,
left: 37,
right: 39,
down: 40,
delete: [8, 46]
}
const keyNames: { [key: string]: string | Array<string> } = {
// #7880: IE11 and Edge use `Esc` for Escape key name.
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
// #9112: IE11 uses `Spacebar` for Space key name.
space: [' ', 'Spacebar'],
// #7806: IE11 uses key names without `Arrow` prefix for arrow keys.
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
// #9112: IE11 uses `Del` for Delete key name.
'delete': ['Backspace', 'Delete', 'Del']
}
function genFilterCode (key: string): string {
const keyVal = parseInt(key, 10)
if (keyVal) {
return `$event.keyCode!==${keyVal}`
}
const keyCode = keyCodes[key]
const keyName = keyNames[key]
return (
`_k($event.keyCode,` +
`${JSON.stringify(key)},` +
`${JSON.stringify(keyCode)},` +
`$event.key,` +
`${JSON.stringify(keyName)}` +
`)`
)
}
用 Map
1 | const classNames = new Map([ |
用 Map 对象和 Object 对象有什么区别呢?
一个对象通常都有自己的原型,所以一个对象总有一个”prototype”键。
一个对象的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
在我看来, 用 Map 和 Object 无论哪个都好, 至少看起来比 if 和 switch 好
一个 if 中的多个条件判断
感觉这个也是一个比较常出现的一个情况, 在一个条件判断语句中, 有多重条件可以通过次验证的情况
可以利用数组来和数组自带的方法来处理这种情况
1 | if ( param === 1 || param === 2 || param === 3 || param === 'a' || param === 'b') {} |
1 | if ( param !== 1 && param !== 2 && param !== 3 && param !== 'a' && param !== 'b') {} |
利用数据和符号, 在可读范围内
在可读范围内使用运算符来简化代码的逻辑
比如 !除了做逻辑运算之外还可以用于取得一个布尔值, 举个例子, 在我们现在是用的 iview 的源码中, 就很多关于!!的使用, 原理就是!!可以把数据转换为布尔类型, 然后用于判断
1 | if (value === '' || value === 0 || value === null || value === undefined) { } |
1 | // 这是iview里的代码片段 |
&&
1 | type === 'drag' && dragOver() |
当然, 其他符号也有自己不同的作用, 也可以根据情况使用, 但是一定要保持在可读范围内
比如 (n&1 ? ‘奇数’ : ‘偶数’) 可以用来判断基数和偶数,
原理是在使用按位与(&)运算时 二进制位数对比都为 1 时才为 1
十进制转换为二进制后, 末位数为 1 即奇数, 末位数为 0 即偶数
同样的按位或(|)运算时 由于浮点数不支持位运算, 所以自动转换为整数, 再进行运算。
因为这个特性, 可以取巧, 用来做向下运算。
所以(1.23|0)结果是为 1
但是以上两种可读性不是很高, 所以不建议使用
避免使用 for…in
遍历对象的时候尽可能少的使用 for…in, 因为 for in 会遍历原型上所能枚举的属性,可以用 Object.keys()来遍历
1 | Object.keys(objParam).forEach(key => { |
尽可能的使用内置方法
在 js 的内置对象中现在已经提供了很多内置方法并且还有各种高阶函数
平时在操作这些内置对象的时候, 如果内置方法可以满足需要的时候, 尽量使用内置方法(大多数时候, 内置方法都可以满足需要)
以数组为例
数组对象
比如如下数组去重(虽然有更简单的 Set 可以用于去重)
1 | const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4] |
现在有一个数组 [0, 1, 2, 3, 4],需要计算数组元素的和
1 | const arr = [0, 1, 2, 3, 4] |
拷贝数组
1 | let arr = [1, 2, 3, 4, 5] |
思考题
使(a==1 && a==2 && a==3)结果为 true