# 了解下js代码的规范吧
# js 语法规范
相比于 html
, js
的规范相对要更多,也要更加严格。
当然,规范是人制作的,那每个人,每家公司都有可能有些不同,下面的内容仅供参考。
# 1. 请始终保持不在一行语句末尾添加分号;
, 除了特殊情况。
对于我本人来说,我是个无分号主义者。我的建议是不要写分号,因为 JavaScript
在所有类 C
语言中是比较独特的,它不需要在每个语句的末尾有分号。在很多情况下,JavaScript引擎
可以确定一个分号应该在什么位置然后自动添加它。此特征被称为 自动分号插入(ASI)。
但就算是这样,有时候我也无奈的需要为一行语句末尾添加分号。
如下代码:
// 正确代码:在定义 name 的末尾我加上了一个分号
const name = 'lxh';
((x) => x + 1)
// 报错代码:在定义 name 的末尾没有分号,所以下面的代码会报错。
const name = 'lxh'
((x) => x + 1)
2
3
4
5
6
7
8
所以以中括号开头的语句尽量少些,避免上面的情况出现。
# 2. 请再也不要使用 var
来命名变量了。
使用 var
来命名变量有太多的不好的地方,导致 es6
新增了 const
和 let
关键字。
对于不可变引用请使用 const
来命名。可变的引用请使用 let
。
到现在为止,我还在不少 vue 代码中看到有人使用 var 关键字来命名变量
// a 不会变
const a = 1
// b 接下来会变
let b = 1
b = 3
2
3
4
5
6
(
js
中的变量类型一般分为 基本类型(字符串, 数值, 布尔类型, null, undefined) 和 复杂类型(object, array, function)。
对于复杂类型的变量应该使用 const
来命名。
const obj = {}
const arr = []
const fun = () => {
return true
}
2
3
4
5
# 3. 请使用全等来替代双等
===
:全等也就是严格等于,它会比较两边变量的数据类型来确定是否全等。
const a = 1
const b = '1'
console.log(a === b) // false
2
3
==
:不严格等于, 不会比较两边变量的数据类型。
const a = 1
const b = '1'
console.log(a == b) // true
2
3
# 4. 善用解构
解构可以说是 es6
最方便的设计了,极大的简化了程序。解构的用法也是多种多样,用的好可以少写很多混乱的代码。
(1) 为对象,数组解构
请注意对象的解构不需要考虑数据的顺序性,而数组需要考虑数据的顺序
const { name, age } = userInfo
const { age, name } = userInfo // 这样也行
const [ one, two ] = num
const [ two, one ] = num // 数据就会出错
2
3
4
5
(2) 10 个字段 取九个字段的集合
// 普通方法
const { a, b, c, d, e, f, r, t, y, z } = word
const newWord = { b, c, d, e, f, r, t, y, z }
// 采用解构来简化程序,这时候虽然 a 没用, 但也是被解构出来了。
const { a, ...newWord } = word
console.log(newWord) // b c d e f r t y z
2
3
4
5
6
7
(3)函数参数解构
// 当不采用解构的时候
function fn (userInfo) {
const age = userInfo.age
const name = userInfo.name
return `我是 ${name}, 今年 ${age} 岁。`
}
// 当采用解构的时候
function fn (userInfo) {
const { age, name } = userInfo
return `我是 ${name}, 今年 ${age} 岁。`
}
// 当采用函数参数解构的时候
function fn ({ age, name }) {
return `我是 ${name}, 今年 ${age} 岁。`
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(4)默认值以及多重解构
默认值 以及 函数参数默认值
// 解构的默认值 当 age 解构不出来的时候, 他的默认值就为 13
const { age = 13, name } = userInfo
// 函数参数默认值
function fn ({ age = 13, name }) {
return `我是 ${name}, 今年 ${age} 岁。`
}
// 当函数参数是一个个的时候 也是可以使用默认值的
function fn (age = 13, name) {
return `我是 ${name}, 今年 ${age} 岁。`
}
2
3
4
5
6
7
8
9
10
11
12
多重解构
在对接接口的时候, 我们一般会拿到这样的数据。最终我们要拿到 rows
将其中的数据渲染在页面上。
const res = {
code: 0,
data: {
rows: [
{},
{}
]
},
msg: 'success'
}
// 以前的做法
const rows = res.data && res.data.rows || []
// 采用解构的方式
const { data: { rows = [] } = {} } = res
// 假如数据为这样的
const res1 = {}
const { data: { rows = [] } = {} } = res1
console.log(rows) // []
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 5. 善用模板字符串,不在使用字符串拼接功能
es6
出了一个模板字符串, 弥补了 es5
对字符串的处理能力不足之处。
var name = 'lxh'
var age = 13
// es5
var str = '我是 ' + name + ', 今年 ' + age + '岁。'
// es6
const str = `我是 ${name}, 今年 ${age} 岁。`
2
3
4
5
6
7
# 6. 对象的使用
对象是个复杂数据类型, 它的值是存储在堆栈里面的。而对象的命名只是对这个堆栈的引用。在使用对象时要非常小心,因为你可能在操作同一个对象。
(1)请使用字面量方式创建对象
// 不好的
const a = new Object()
// 好的
const b = {}
2
3
4
5
(2)请别用保留字来当做对象的键值
// 错误的
const a = {
default: true,
name: '123'
}
2
3
4
5
(3)针对对象的属性是方法时,请使用简写的方式
// 不简写
const a = {
fn: function () {}
}
// 简写
const a = {
fn () {}
}
2
3
4
5
6
7
8
9
(4) 对象属性也建议采用简写的方式
// 不简写
const name = 'lxh'
const age = 13
const a = {
name: name,
age: age
}
// 采用简写
const a = {
name,
age
}
// 有变量 也有常量的时候, 请把简写写在一起, 不简写的写在一起
const a = {
name,
age,
id: '123123',
code: '3624'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 7. 扩展运算符的使用
如果你要复制一个数组或者一个对象, 都可以采用 es6
的扩展运算符, 简单方便。
但是要特别注意,扩展运算符的复制只是浅复制,而非深复制。使用时要特别注意这点。
// 数组
const arr = [1, 2, 3, 4]
const copyArr = [...arr]
const arr2 = [...arr, 5, 6, 7]
// 对象
const obj = { age: 13, name: 'lxh' }
const copyObj = { ...obj }
const obj2 = { ...obj, id: '123123', code: '3624' }
2
3
4
5
6
7
8
9
# 8. 数组的使用
(1)请使用字面量方式创建数组
// 不好的
const a = new Array()
// 好的
const b = []
2
3
4
5
(2)在操作数组时,请避免使用 for
循环等基础语句,而应该使用 forEach
, map
, filter
等高阶函数来处理数组。
在对于单一语句的情况下,请省略 return
或大括号
const arr = [1, 2, 3, 4, 5, 6]
// 使用 for
for (let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
// 使用 forEach
arr.forEach(i => console.log(i))
2
3
4
5
6
7
8
# 9. 字符串的使用
请统一使用使用 单引号来操作字符串。少按两下键盘不舒服吗?
const name = "lxh"
const name = 'lxh'
2
3
# 10. 函数的使用
(1) 函数参数的多种用法
// 普通
function fn (name, age, id, code, user, healthy) {
const params= { id, code, user, healthy }
// todo
return `我是 ${name}, 今年 ${age} 岁。`
}
// 默认值
function fn (name, age = 13, id, code, user, healthy) {
const params= { id, code, user, healthy }
// todo
return `我是 ${name}, 今年 ${age} 岁。`
}
// 扩展符来充当参数
function fn (name, age = 13, ...ohterParams) {
const params = ohterParams
// todo
return `我是 ${name}, 今年 ${age} 岁。`
}
// 获取所有参数
function fn (...args) {
}
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
# 11. 不要去修改内置对象原型
有些人喜欢为 String
的原型上挂载方法, 以简化引用。
String.prototype.handleStr = function () {
}
2
3
# 12. 该使用 class
去代替原型了
// 原型
function Q () {
// todo
}
Q.prototype.handleStr = function () {}
Q.prototype.handleArr = function () {}
// 类的方式
class Q {
constructor () {
}
handleStr () {
}
handleArr () {
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 13. 怎么去使用 Promise
和 async await
下面是几个 封装的axios 请求, axios 请求返回一个 Promise。
function getData () {
return new Promise((resolve, reject) => {
$http({
url: 'http://www.baidu.com',
type: 'post',
data: {}
}).then(res => {
const { code } = res
$http({
url: 'http://www.baobao.com',
type: 'post'
}).then(res2 => {
// TODO 处理接下来逻辑
resolve(res2)
}).catch(err => reject(err))
}).catch(err => reject(err))
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可以发现,在这种很多的 Promise
处理时,有着嵌套地狱的风险。
下面是合理的使用 Promise
和 async await
,可以发现采用同步处理,整个逻辑层次都清晰起来了, 最后再用 Promise
的语法糖来返回一个 Promise
。
async function getData () {
try {
const { code } = await $http({
url: 'http://www.baidu.com',
type: 'post',
data: {}
})
const res2 = await $http({
url: 'http://www.baobao.com',
type: 'post',
})
// TODO 处理接下来逻辑
Promise.resolve(res2)
} catch (err) {
Promise.reject(err)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
可以发现, 大部分的规范都围绕着 es6
来进行,确实 es6
让整个代码变得更加优雅了,所有我们要善于使用es6
。
# js 代码规范
不同的人的代码规范更加是千奇百怪,但只有一个目的,就是将代码写的清晰。
# 1. 空格 与 空行
善于在某些地方使用正确的空格会让你的代码变得更加清晰的。
// 这是没有空格的
async function getData(){
try {
const {code} = await $http({
url:'http://www.baidu.com',
type:'post',
data:{}
})
const res2 = await $http({
url:'http://www.baobao.com',
type:'post',
})
// TODO 处理接下来逻辑
Promise.resolve(res2)
} catch(err){
Promise.reject(err)
}
}
// 这是有空格 并且加上一些空行的
async function getData () {
try {
const { code } = await $http({
url: 'http://www.baidu.com',
type: 'post',
data: {}
})
const res2 = await $http({
url: 'http://www.baobao.com',
type: 'post',
})
// TODO 处理接下来逻辑
Promise.resolve(res2)
} catch (err) {
Promise.reject(err)
}
}
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
44
# 2. 注释
合理的注释会让阅读你代码的人心情愉悦, 而不会想着去某宝买把刀。
普通注释
// 获取数据
async function getData () {
// TODO 处理接下来逻辑
}
2
3
4
针对重要功能,逻辑复杂的功能的注释
/**
* @desc 获取数据方法
* @param { String } url
* @param { String } type
* @param { Object } data
*/
async function getData (url, type, data) {
// TODO 处理接下来逻辑
}
2
3
4
5
6
7
8
9
# 3. 拖尾逗号
在 es5
中, 拖尾逗号是合法的。但是在 IE8
(非 IE8 文档模式)下,当出现拖尾逗号,则会抛出错误。
const obj = {
name: 'lxh',
age: 13, // 这就是拖尾逗号
}
2
3
4
# 4. 构造函数参数
在 js
中, 通过 new
调用构造函数时,如果不带参数,可以省略后面的圆括号。
// 合法的
const P = new Person
// 但是为了一致性,请加上圆括号
const P = new Person()
2
3
4
5
# 4. 链式声明赋值
// 针对多个变量的声明赋值,有的人会这样写
let a = 1, b = 2, c = 3
// 建议这样写
let a = 1
let b = 2
let c= 3
2
3
4
5
6
7
8
# 5. 长代码变短代码
尽量不要写很长的代码,实在是很难看。
// 请看这个长代码(好吧,其实还不算长)
const index = [1, 2, 3, 4, 5, 6, 7, 8].findIndex(i => i === 1 && i % 2 !== 0)
// 拆分为短代码
const arr = [1, 2, 3, 4, 5, 6, 7, 8]
const index = arr.findIndex(i => {
return i === 1 && i % 2 !== 0
})
2
3
4
5
6
7
8
# 6. 代码复用
千万别觉得抽离一个函数出来更浪费时间,总有某个时刻你会发现你真的很聪明的。
# 7. 上线前删除掉所有 console.log
在浏览器中, console.log
其实是个很耗费性能的代码。将它删除可以提升程序运行的速度。