变量
- 名称应该是可描述、有意义的
- 小驼峰或是大驼峰书写。
- 名称不要有冗余的上下文
声明经常复用的常量,全局常量可以用全大写字母、下划线分割单词风格书写。
函数
名称要有意义
- 不要害怕太长
- 通常是动词
- 使用默认参数而不是在函数体内额外的条件语句
- 限制参数数量
- 如果参数过多:
- 函数要做的事情太多,需要拆分
- 参数应该作为专用数据结构传递(对象
- 如果参数过多:
- 一个函数别做太多事情
- 如果只用一个布尔值就能分为没重复的两部分,那干脆就拆成两个函数
- 有大量重复代码,能复用的情况坚决复用。(有点废话,但是有时确实需要自己提醒一下自己)
保持纯函数,避免副作用——直接返回新值,而不是操作传入的数据
不要双重否定——
!isNotxxx
尽可能简写——
!!
将其他任何值转换为布尔值if (firstName !== "" && firstName !== null && firstName !== undefined) {
// ...
}
//better ✅
if (!!firstName) {
// ...
}
减少分支,尽早return,使代码线性化、更具可读性且不那么复杂
使用map>借用对象>switch>if、else。(下文详细讲)
使用可选链接
?.
??
- 关于??
const email = user?.email ?? "N/A";
并发
- 关于??
使用Promise减少回调防止代码嵌套过深
- 或者Async 和 Await
```javascript
do1(function (err, xxx) {
do2(a1, function (err, xxx) {
do3(a2, function (err, xxx) {
}); }); });do4(a3, function (err, xxx) {
doErr(a4, function (err) {
throw new Error(err);
});
});
// better ✅ do1() .then(do2) .then(do3) .then(do4) .catch((err) => throw new Error(err);
// or using Async/Await ✅
async function doSth() { try { const b1 = await do1(); const b2 = await do2(b1); const b3 = await do3(b2); const b4 = await do4(b3); return do5(b4); } catch (e) { throw new Error(err); } }
<a name="BpQdW"></a>
## 错误处理
处理抛出的错误和reject的promise
```javascript
try {
// Possible erronous code
} catch (e) {
console.log(e);
}
// better ✅
try {
// Possible erronous code
} catch (e) {
// Follow the most applicable (or all):
// 1- More suitable than console.log
console.error(e);
// 2- Notify user if applicable
alertUserOfError(e);
// 3- Report to server
reportErrorToServer(e);
// 4- Use a custom error handler
throw new CustomError(e);
}
注释
- 只注释业务逻辑,太简单的不要注释
- 所以也需要代码写的可读
使用git版本控制从而在
git log
查看历史,而不是依靠注释一些优雅的书写方法
或许不用if else
三元运算符
-
?? 运算符
??
运算符的使用 ```javascript const sthLog = sth ?? “none” console.log(sth)
//等效于 if(sth){ console.log(sth) }else{ console.log(“none”) }
<a name="AFsHl"></a>
### 短路评估
```javascript
if(flag){
doSth()
}
//短路
flag && doSth()
如果非常多if else
switch
很明显,第一个想到的应该就是用switch
。这应该没什么好说的。
借用对象?
将判断条件作为对象的属性名,将处理逻辑作为对象的属性值,在触发的时候,通过对象属性查找的方式来进行逻辑判断,这种写法适合一元条件判断的情况。
Map
Map与Obecj的区别在于键的设置可以是任意值
这里分享一个我看到的写的非常好的代码片段——
- 判断条件复杂
- 多元判断
- 有重复的处理逻辑
- 凡是guest情况都要发送一个日志埋点,不同status情况也需要单独的逻辑处理
```javascript
const actions = ()=>{
const functionA = ()=>{/do sth/}
const functionB = ()=>{/do sth/}
const functionC = ()=>{/send log/}
return new Map([
//前面的是身份标识,后面数字是活动状态
[/^guest[1-4]$/,functionA],
[/^guest_5$/,functionB],
[/^guest.$/,functionC],
[/^master_1$/, ()=>{/do sth*/}],
]) }[/^master_2$/', ()=>{/*do sth*/}],
const onButtonClick = (identity,status)=>{
let action = […actions()].filter(([key,value])=>(key.test(${identity}_${status}
)))
action.forEach(([key,value])=>value.call(this))
}
**小技巧:**拼接为字符串后利用正则表达式
<a name="o89j6"></a>
## 从数组中删除重复项
借助Set,将原数组转为Set 后再转换为数组
- new Set()将原数组转为Set——此时删除了重复项
- 展开运算符再将其转换为数组
```javascript
const uniqueArr = [...new Set(Arr)]
可选链?.
有时你不能确定待放问的属性究竟存不存在,如果访问了不存在的属性,那必然会崩溃报错。如果还用if-else
或者&&
连一串判断,又属实拉垮了。
console.log(human?.wing)//不存在的话就会打印 undefined
交换变量
借助解构赋值
[a,b] = [b,a]
将其他值转换为布尔值
扩展运算符
[...xxx]
将xxx
(一个可迭代的对象)转换为数组。
- 可以用来合并数组
- 在数组中添加东西
- 与push的区别就是 它返回的是一个新的数组,而不是在原来的数组上操作——有没有想到纯函数呢
解构赋值
const human = {
age:18,
name:'zzz',
height:180,
weight:130,
}
const {age,name,...stature} = human
模板字符串
使用xxx${variable}xxx
而不是'xxx'+variable+'xxx'
数组中查询特殊数据
find(callback)
```javascript for (let i = 0; i < humans.length; ++i) { if (humans[i].height >= 170) { tallMan = humans[i]; } }
- 与push的区别就是 它返回的是一个新的数组,而不是在原来的数组上操作——有没有想到纯函数呢
// better tallMan = humans.find((human) => human.height === >= 170);
<a name="J0EgW"></a>
## for与forEach
```javascript
for(let i = 0;i < arrs.length; i++){
doSth(arrs.[i])
}
//better
arrs.forEach((arr) => doSth(arr))
对象的keys和values
Object.keys()
将对象的所有键收集到一个新数组中Object.values()
将对象的所有值收集到一个新数组中includes() 和 indexOf()
也许这两个方法都能很好的判断某个值究竟在不在数组之中,但是或许使用includes()
的语义更为明显。压缩判断条件
很长的||
总是令人讨厌的,也许能取代掉它。 ```javascript if(num == 1 || num == 2 || num == 3){ console.log(“Yay”); }
// better if([1,2,3].includes(num)){ console.log(“Yay”); }
<a name="GghLS"></a>
## 或许不用Math
- `~~` 也可以对一个数字四舍五入
- `**` 也可以对一个数字幂运算
- `|` 将float 转 int
```javascript
// chars[Math.floor(Math.random() * chars.length)]
chars[(Math.random() * chars.length) | 0]
类中自动绑定
截取数组
- 直接改短数组的
length
可以简洁地删去数组后面的部分 - slice 是较快的