function howManyDays(month) {
if (month === 1) {
return 2
} else if (month === 2) {
return 2
} else {
return 3
}
}
//change to
function howManyDays(month) {
let table = {
1: 1,
2: 2,
3: 3,
default: 'error'
}
return table[month] || table['default']
}
JS
命名
普通变量/属性用「名词」
let person = {
name: 'Frank'
}
布尔变量
let person = {
dead: false, // 如果是形容词,前面就没必要加 is,比如isDead
canSpeak: true, //情态动词有 can、should、will、need 等,情态动词后面接动词
isVip: true, // be 动词有 is、was 等,后面一般接名词
hasChildren: true, // has 加名词
}
普通函数/方法用「动词」开头
let person = {
run(){}, // 不及物动词
drinkWater(){}, // 及物动词
eat(foo){}, // 及物动词加参数(参数是名词)
}
回调、钩子函数用「介词」开头,或用「动词的现在完成时态」
var component = {
beforeCreate(){},
created(){},
}
容易混淆的地方加前缀
属性访问器函数可以用名词
介词一致性
若使用了 before + after,那么就在代码的所有地方都这样用,若使用了 before + 完成时,那么就坚持这样
顺序一致性
updateContainerWidth 和 updateHeightOfContainer
表里一致性
函数名必须完美体现函数的功能,不多也不少,否则要么改函数名,要么写多个函数
避免全局查找
重复使用的调用结果,事先保存到局部变量, 避免全局变量
function fun() {
console.log(window.location.href + window.location.host)
}
//change to
function fun() {
let location = window.location
console.log(location.href + location.host)
}
循环
将不需要重复计算的逻辑外提
缓存变量
使用哨兵值加速循环
不要在循环内部或要求性能的函数中使用try-catch-finally
条件分支
知道答案,直接返回
按可能性顺序从高到低调整判断顺序
用map or obj代替复杂分支
在同一条件的多(>2)条件分支时,使用switch优于if
使用三目运算符替代条件分支
使用字面量
let obj = {},
arr = [],
reg = /[A-Z]/
使用常量(避免魔法数字)
如一天是 86400 秒
使用默认函数参数和解构
const test = ({ name = 'Jack' } = {}) => console.log(name)
字符串连接
如果要连接多个字符串,应该少使用+=,如:x += a;x += b;x += c 应该写成 x += a + b + c 而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来
let arr = []
for (let i = 0; i< 100; i++) {
arr.push(i.toString())
}
let str = arr.join("")
类型转换(总是检查数据类型)
数字转换成字符串 ("" +) > String() > .toString() > new String()
let n = 0
function fun() {
n++
if (n < 10) setTimeout(fun, 10)
}
fun()
//change to
let m = 0
function fun2() {
m++
if (m >= 10) clearTimeout(timer)
}
let timer = setInterval(fun2, 10)
避免with、eval、Function
DOM
尽量
尽量减少DOM操作
尽量使用局部变量
尽量只获取元素节点
尽量使用最新的API
尽量在appendChild前操作
使用DocumentFragment优化多次append
for (let i = 0; i < 100; i++) {
let el = document.createElement('p')
el.innerHTML = i
document.body.appendChild(el)
}
//change to
let fragment = document.createDocumentFragment()
for (let i = 0; i < 100; i++) {
let el = document.createElement('p')
el.innerHTML = i
fragment.appendChild(el)
}
document.body.appendChild(fragment)
使用一次innerHTML赋值代替构建dom元素
对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多
let fragment = document.createDocumentFragment()
for (let i = 0; i < 100; i++) {
let el = document.createElement('p')
el.innerHTML = i
fragment.appendChild(el)
}
document.body.appendChild(fragment)
let html = []
for (let i = 0; i < 100; i++) {
html.push(`<p>${i}</>`)
}
document.body.innerHTML = html.join("")
通过模板元素clone,替代createElement
var fragment = document.createDocumentFragment()
var pE1 = document.getElementsByTagNames('p')[0]
for (let i = 0; i< 100; i++) {
var el = pE1.cloneNode(false)
el.innerHTML = i
fragment.appendChild(el)
}
document.body.appendChild(fragment)
使用firstChild和nextSibling代替childNodes遍历dom元素
for (let i = 0; i < element.childNodes.length; i++) {
//...
}
var node = element.firstChild
while (node) {
//...
node = node.nextSibling
}
function init() {
var el = document.getElementById('app')
el.onclick = function() {
//...
}
//Note
el = null
}
//solution 2
function elClickHandler(){}
function init() {
var el = document.getElementById('app')
el.onclick = elClickHandler
}