# 了解下js代码的规范吧

# js 语法规范

相比于 html, js 的规范相对要更多,也要更加严格。

当然,规范是人制作的,那每个人,每家公司都有可能有些不同,下面的内容仅供参考。

# 1. 请始终保持不在一行语句末尾添加分号;, 除了特殊情况。

对于我本人来说,我是个无分号主义者。我的建议是不要写分号,因为 JavaScript 在所有类 C 语言中是比较独特的,它不需要在每个语句的末尾有分号。在很多情况下,JavaScript引擎 可以确定一个分号应该在什么位置然后自动添加它。此特征被称为 自动分号插入(ASI)。

但就算是这样,有时候我也无奈的需要为一行语句末尾添加分号。

如下代码:

// 正确代码:在定义 name 的末尾我加上了一个分号
const name = 'lxh';
((x) => x + 1)


// 报错代码:在定义 name 的末尾没有分号,所以下面的代码会报错。
const name = 'lxh'
((x) => x + 1)
1
2
3
4
5
6
7
8

所以以中括号开头的语句尽量少些,避免上面的情况出现。

# 2. 请再也不要使用 var 来命名变量了。

使用 var 来命名变量有太多的不好的地方,导致 es6 新增了 constlet 关键字。

对于不可变引用请使用 const 来命名。可变的引用请使用 let

到现在为止,我还在不少 vue 代码中看到有人使用 var 关键字来命名变量

// a 不会变
const a = 1

// b 接下来会变
let b = 1
b = 3
1
2
3
4
5
6

( js 中的变量类型一般分为 基本类型(字符串, 数值, 布尔类型, null, undefined) 和 复杂类型(object, array, function)。 对于复杂类型的变量应该使用 const 来命名。

const obj = {}
const arr = []
const fun = () => {
  return true
}
1
2
3
4
5

# 3. 请使用全等来替代双等

=== :全等也就是严格等于,它会比较两边变量的数据类型来确定是否全等。

const a = 1
const b = '1'
console.log(a === b) // false
1
2
3

== :不严格等于, 不会比较两边变量的数据类型。

const a = 1
const b = '1'
console.log(a == b) // true
1
2
3

# 4. 善用解构

解构可以说是 es6 最方便的设计了,极大的简化了程序。解构的用法也是多种多样,用的好可以少写很多混乱的代码。

(1) 为对象,数组解构

请注意对象的解构不需要考虑数据的顺序性,而数组需要考虑数据的顺序

const { name, age } = userInfo
const { age, name } = userInfo // 这样也行

const [ one, two ] = num
const [ two, one ] = num // 数据就会出错
1
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
1
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} 岁。`
}
1
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} 岁。`
}

1
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) // []
1
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} 岁。`
1
2
3
4
5
6
7

# 6. 对象的使用

对象是个复杂数据类型, 它的值是存储在堆栈里面的。而对象的命名只是对这个堆栈的引用。在使用对象时要非常小心,因为你可能在操作同一个对象。

(1)请使用字面量方式创建对象

// 不好的
const a = new Object()

// 好的
const b = {}
1
2
3
4
5

(2)请别用保留字来当做对象的键值

// 错误的
const a = {
  default: true,
  name: '123'
}
1
2
3
4
5

(3)针对对象的属性是方法时,请使用简写的方式

// 不简写
const a = {
  fn: function () {}
}

// 简写
const a = {
  fn () {}
}
1
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'
}
1
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' }
1
2
3
4
5
6
7
8
9

# 8. 数组的使用

(1)请使用字面量方式创建数组

// 不好的
const a = new Array()

// 好的
const b = []
1
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))
1
2
3
4
5
6
7
8

# 9. 字符串的使用

请统一使用使用 单引号来操作字符串。少按两下键盘不舒服吗?

const name = "lxh"

const name = 'lxh'
1
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) {

}
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

# 11. 不要去修改内置对象原型

有些人喜欢为 String 的原型上挂载方法, 以简化引用。

String.prototype.handleStr = function () {

}
1
2
3

# 12. 该使用 class 去代替原型了

// 原型
function Q () {
  // todo
}

Q.prototype.handleStr = function () {}
Q.prototype.handleArr = function () {}

// 类的方式

class Q {
  constructor () {

  }

  handleStr () {

  }

  handleArr () {
    
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 13. 怎么去使用 Promiseasync 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))
  })
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

可以发现,在这种很多的 Promise 处理时,有着嵌套地狱的风险。

下面是合理的使用 Promiseasync 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)
  }
      
}

1
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)
  }
      
}
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
44

# 2. 注释

合理的注释会让阅读你代码的人心情愉悦, 而不会想着去某宝买把刀。

普通注释

// 获取数据
async function getData () {
  // TODO 处理接下来逻辑
}
1
2
3
4

针对重要功能,逻辑复杂的功能的注释

/**
  * @desc 获取数据方法
  * @param { String } url
  * @param { String } type
  * @param { Object } data
  */
async function getData (url, type, data) {
  // TODO 处理接下来逻辑
}
1
2
3
4
5
6
7
8
9

# 3. 拖尾逗号

es5 中, 拖尾逗号是合法的。但是在 IE8 (非 IE8 文档模式)下,当出现拖尾逗号,则会抛出错误。

const obj = {
  name: 'lxh',
  age: 13, // 这就是拖尾逗号
}
1
2
3
4

# 4. 构造函数参数

js 中, 通过 new 调用构造函数时,如果不带参数,可以省略后面的圆括号。

// 合法的
const P = new Person

// 但是为了一致性,请加上圆括号
const P = new Person()
1
2
3
4
5

# 4. 链式声明赋值

// 针对多个变量的声明赋值,有的人会这样写
let a = 1, b = 2, c = 3

// 建议这样写
let a = 1
let b = 2
let c= 3

1
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
})
1
2
3
4
5
6
7
8

# 6. 代码复用

千万别觉得抽离一个函数出来更浪费时间,总有某个时刻你会发现你真的很聪明的。

# 7. 上线前删除掉所有 console.log

在浏览器中, console.log 其实是个很耗费性能的代码。将它删除可以提升程序运行的速度。

上次更新: 10/14/2022, 4:05:31 PM