前端代码整洁与开发技巧
为保证前端人员在团队项目开发过程中的规范化、统一化,特建立《前端代码整洁与开发技巧》文档,通过代码简洁推荐、开发技巧推荐等章节来帮助我们统一代码规范和编码风格,从而提升项目的可读性和可维护性。
一、代码整洁推荐
1.1 三元(三目)运算符
如果只想在一行中编写if…else语句时,这是一个很好的节省代码的方式。
常规:
const x = 20 let answer if(x > 10) { answer = '大于10' }else { answer = '小于等于10' }
简写:
const x = 20 const answer = x > 10? '大于10' : '小于等于10'
嵌套版三元运算:
const x = 20 const answer = x > 10? '大于10' : x < 5? '小于5' : '在5和10之间' // 第二层加上()增强可读性 const answer = x > 10? '大于10' : (x < 5? '小于5' : '在5和10之间')
注意:三元运算不要超过2层嵌套,否则可读性不强,如果是嵌套两层,要求第二层加上()帮助提升可读性。
1.2 短路判断简写
将变量值分配给另一个变量时,可能希望确保源变量不为null,undefined或为空。这时候可以编写带有多个条件的长 if 语句,也可以使用短路判断。
常规:
if(type !== null || type !== undefined || type !== '') { let wtType = type } else { let wtType = '01' }
简写:
let wtType = type || '01'
注意:如果type值为false或者数字0将取值为字符串’01’。
1.3 变量声明简写
在进行连续性的变量声明操作时,应尽可能的使用 一次声明语句来提升程序运行效率。
常规:
let x let y let z = 1
简写:
let x, y, z = 1
1.4 if真值判断简写
这可能是微不足道的,但值得一提。在执行“if 检查”时,有时可以省略全等运算符。
常规:
if(likeJavascript === true) { ... } if(likeNode !== true) { ... }
简写:
if(likeJavascript) { ... } if(!likeNode) { ... }
1.5 For循环简写
常规:
const arr = [1, 2, 3] for(let i = 0; i < arr.length; i++) { console.log(i, arr[i]) if(arr[i] > 1) { break } } // 0, 1 // 1, 2
如果不需要访问索引,请执行以下操作:
for(let item of arr) { console.log('item', item) if(item > 1) { break } } // 1 // 2
如果只想访问索引,请执行以下操作:
for(let index in arr) { console.log(index) } // 1 // 2 // 3
如果要访问对象中的键,请执行以下操作
const obj = {name: 'zhangsan', age: 18} for(let key in obj) { console.log(key,obj[key]) } // name // age
注意:不能使用for…of 来遍历对象。
1.6 对象属性简写
ES6提供了一种更简单的方法来为对象分配属性。如果变量名称与对象键相同,则可以使用简写表示法。
常规:
let signType = '1' let params = { signType: signType }
简写:
let signType = '1' let params = { signType }
1.7 箭头函数简写
经典函数以简单的形式易于读写,但是一旦你开始将它们嵌套在其他函数调用中,它们往往会变得有点冗长和混乱。
常规:
function sayHello(name) { console.log('Hello', name) } setTimeout(function() { console.log('Loaded') }, 2000) list.forEach(function(item) { console.log(item) })
简写:
const sayHello = name => console.log('Hello', name) setTimeout(() => console.log('Loaded'), 2000) list.forEach(item => console.log(item))
1.8 隐式返回简写
Return 是我们经常使用的关键字,用于返回函数的最终结果。具有单个语句的箭头函数将隐式返回其执行结果(函数可以省略大括号{}用()省略return关键字,具体可参考下例)。
要返回多行语句(例如对象),必须使用 () 而不是 {} 来包装函数体。这可确保将代码执行为单个语句。
常规:
function sum(x, y) { return x + y } function makeInfo(name, age) { return {name, age} }
简写:
const sum = (x, y) => x + y const makeInfo = (name, age) => ({name, age})
1.9 模板字符串
您是否厌倦了使用 ‘+’ 将多个变量连接成一个字符串?有没有更简单的方法?如果你能够使用ES6,那么你很幸运。您需要做的就是使用反引号,并使用 ${} 来包含变量。
常规:
const name = 'zhangsan' const age = 18 let des = name + '今年' + age + '岁'
简写:
const name = 'zhangsan' const age = 18 let des = `${name}今年${age}岁`
1.10 默认参数值
您可以使用if语句定义函数参数的默认值。在ES6中,您可以在函数声明本身中定义默认值。
常规:
function volume(l, w, h) { if(w === undefined) { w = 3 } if(h === undefined) { h = 4 } return l * w * h }
简写:
const volume = (l, w = 3, h = 4) => l * w * h volume(2) // 24
注意:只有w,h为undefined时默认值才会生效。
结构赋值中的默认值也是如此,如果值为null默认值不会生效,如:
const res = { list: null, code: undefined } const { list = [], code = 1 } = res console.log(list) // null console.log(code) // 1 let num = list.length // Uncaught TypeError: Cannot read properties of null (reading 'length')
注意:如果直接取list数组的长度或者利用[index]取里面的值在res.list为null或者不为数组的时候可能会发生报错,针对该问题,大家可以在解构的时候不赋默认值,在解构的下方利用null判断运算符来处理默认值,如:
const res = { list: null } let { list , code = 1 } = res list = list ?? [] console.log(list) // [] let num = list.length // 0
1.11 解构赋值简写
对数组和变量进行解构可以减少变量滥用,提升程序的运行效率。
常规:
let params = { wtId: this.transferDetail.wtId, newPic: type === '01' ? this.selectPersonId : '', // type是方法入参 oldPic: this.transferDetail.picOld, recordId: this.applyId, // 转派记录 replacementPicStatus: '02', // 转派状态 01-转派中 02-转派结束 replacementReason: this.replacementReason }
简写:
const { selectPersonId, applyId, replacementReason, transferDetail } = this let params = { wtId: transferDetail.wtId, newPic: type === '01' ? selectPersonId : '', // type是方法入参 oldPic: transferDetail.picOld, recordId: applyId, // 转派记录 replacementPicStatus: '02', // 转派状态 01-转派中 02-转派结束 replacementReason }
解构知识点链接地址:https://es6.ruanyifeng.com/#docs/destructuring
1.12 多条件判断简写
常规:
function typeHandle(type) { if (type === 'test1') { test1(); } else if (type === 'test2') { test2(); } else if (type === 'test3') { test3(); } else if (type === 'test4') { test4(); } else { throw new Error('Invalid value ' + type); } } typeHandle('test3')
简写:
function typeHandle(type) { const types = { test1: test1, test2: test2, test3: test3, test4: test4 }; let func = types[type]; (!func) && throw new Error('Invalid value ' + type); func(); } typeHandle('test3')
1.13 多变量赋值简写
常规:
let test1, test2, test3; test1 = 1; test2 = 2; test3 = 3; let name, age, sex; name = 'zhangsan'; age = '18'; sex = '男'
简写:(利用es6数组、对象的结构赋值,实现多变量赋值简写)
let [test1, test2, test3] = [1, 2, 3]; let {name, age, sex} = { name: 'zhangsan', age: '18', sex: '男'};
1.14 解构时重命名
常规:
const { ticketTypeName } = this.tciketDetail let params = { wtName: ticketTypeName, ... }
简写:
const { ticketTypeName: wtName } = this.tciketDetail let params = { wtName, ... }
对象解构赋值的简写形式:
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" foo // error: foo is not defined
1.15 对象替代switch
常规:
// 获取工作票名称 workTicketName(type) { switch (type) { case '01': return '变一' break case '02': return '变二' break case '03': return '配一' break case '04': return '配二' break case '05': return '低压' break case '06': return '作业卡' break case '07': return '派工单' break default: break } } workTicketName('01') // 变一
简写:
// 获取工作票名称 workTicketName(type) { const typeObj = { '01': '变一', '02': '变二', '03': '配一', '04': '配二', '05': '低压', '06': '作业卡', '07': '派工单' } return typeObj[type] } workTicketName('01') // 变一