【最新最全】前端开发规范系列-JS篇

为什么做这件事
目标市面上有很多前端开发规范,有的过于成旧,有的过于简单、片面,好未来培优增长前端团队针对目前这些问题,整理了一份最新最完整的前端开发规范,包括JS、CSS、HTML、lint、Vue等。
做这件事的意义

  1. 提高代码的可读性和可维护性。
    有统计显示,在一个中大型项目中,代码的后期维护成本远高于开发成本。所以,提高代码的可维护性能极大减低项目的维护成本。
  2. 实现项目研发的标准化。
    目前的项目研发流程类似于汽车等工业产品的流水线生产模式,通过开发规范,能有利于研发的标准化。
  3. 减少bug、利于代码审查。
    在艺术的世界里我们提倡天马行空,但是,在代码的世界里,我们要提倡开发规范,这样会减少bug的数量和降低问题的排查时间。
JS篇 1、代码风格
1.1、编码格式 JavaScript 文件使用无 BOM 的 UTF-8 编码。
ps: UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。
1.2、代码缩进 使用 2 个空格缩进
1.3、代码空格 1.3.1、二元运算符两侧各有一个空格,一元运算符与操作对象之间不允许有空格
// bad let a=12 a=b+c a ++// good let a = 14 a = b + c a++

1.3.2、代码块起始的左花括号 { 前有一个空格。
// bad if (condition){ } while (condition){ } function funcName(){ }// good if (condition) { } while (condition) { } function funcName() { }

1.3.3、if / else / for / while / function / switch / do / try / catch / finally 关键字后,有一个空格。
// bad if(condition) { } while(condition) { }// good if (condition) { } while (condition) { }

1.3.4、在对象创建时,属性中的 : 之后有一个空格,: 之前不允许有空格。
// bad var obj = { a : 1, b:2, c :3 }// good var obj = { a: 1, b: 2, c: 3 }

【【最新最全】前端开发规范系列-JS篇】##### 1.3.5、函数声明、具名函数表达式、函数调用中,函数名和 ( 之间不允许有空格。
// bad function funcName () { const func = function (){} funcName ()// good function funcName() { } const funcName = function() { } funcName()

2、变量声明
2.1、const, let ,var 对所有变量尽量都使用const let ,尽量不要使用var。
ps:这样做可以确保你无法重新分配引用,以避免出现错误和难以理解的代码。
另外将所有的 const 和 let 分组 。 如果没有写关键字,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突,另外,也很难明确该变量的作用域是什么。
// bad var a = 1// good const a = 1 const b = 2 let c = 3 let d = 4

2.2、保留字 别使用保留字作为对象的键值,这样在 IE8 下不会运行
// bad const a = { default: {},// default 是保留字 common: {} }// good const a = { defaults: {}, common: {} }

2.3、引号问题 对字符串使用单引号 ,尽量不使用双引号。
ps: 因为大多时候我们的字符串。特别html会出现双引号
// bad const a = "123"// good const a = '123'

2.4、分号问题 以下几种情况结尾可不带分号
声明变量时、import、export、return、throw、break
ps:不带分号简洁明了,并且根据ASI【Automatic Semicolon Insertion】机制,解析时会自动给插入分号
// bad let a = 12; import xxx from 'aa'; return; throw new Error(err); break; // good let a = 12 import xxx from 'aa' return throw new Error(err) break

2.5、链式赋值 变量不要进行链式赋值,变量链式赋值会创建隐藏的全局变量
// bad let a = b = 2// good let a = 2 let b = 2

2.6、多余变量 不允许出现未被使用的变量,声明但未被使用的变量通常是不完全重构犯下的错误,这种变量在代码里浪费空间并会给读者造成困扰
3、创建变量
3.1、创建对象变量 请使用字面量值创建
ps: 代码量少,易读性高,运行速度快
// bad const a = new Object() const b = new Array()// good const a = {} const b = []

3.2、创建函数 不要使用Function构造函数创建函数
ps:代码量少,易读性高,运行速度快
// bad const add = new Function('a', 'b', 'return a + b')// good const func1 = function() {}

3.3、创建字符串变量 字符串太长的时候,建议不要使用字符串连接符换行\,而是使用 +
// bad const string = '好未来\ 是一家非常好的教育公司\ 是真的非常好'// good const str = '好未来' + '是一家非常好的教育公司' + '是真的非常好' 程序化生成字符串时,建议使用模板字符串 const test = 'test' // bad const str = 'a' + 'b' + test// good const str = `ab${test}`

4、箭头函数
4.1、当你必须使用函数表达式(比如传递匿名函数)时,使用箭头函数标记 ps:它将创建在 this 上下文中执行的函数版本,通常是您想要的,并且语法更简洁
// bad [1, 2, 3].map(function(x) { const y = x + 1 return x * y })// good [1, 2, 3].map(x => { const y = x + 1 return x * y })

4.2、箭头函数中参数的括号问题 箭头函数如果是只有一个参数时不加括号,简介明了
// bad [1,2,3].map((x) => { const y = x + 1 return x * y })// good [1,2,3].map(x => { const y = x + 1 return x * y })

4.3、如果函数体只包含一条没有副作用的返回表达式的语句,可以省略花括号并使用隐式的 return, 否则保留花括号并使用 return 语句
// bad [1, 2, 3].map(number => { const nextNumber = number + 1 `A string containing the ${nextNumber}` })// good [1, 2, 3].map(number => `A string containing the ${number}`)

5、解构赋值
ps:解构可以避免创建属性的临时引用
5.1、对象解构 当需要使用对象的多个属性时,请使用解构赋值
// bad function getFullName(user) { const firstName = user.firstName const lastName = user.lastName return `${firstName} ${lastName}` }// good function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}` }

5.2、数组解构 当需要使用数组的多个值时,请同样使用解构赋值
const arr = [1, 2, 3, 4]// bad const first = arr[0] const second = arr[1]// good const [first, second] = arr

5.3、函数回传参数的解构 函数需要回传多个值时,请使用对象的解构,而不是数组的解构。
ps: 这样可以非破坏性地随时增加或者改变属性顺序
// bad function doSomething() { return [top, right, bottom, left] } // 如果是数组解构,那么在调用时就需要考虑数据的顺序 const [top, xx, xxx, left] = doSomething()// good function doSomething() { return { top, right, bottom, left } } // 此时不需要考虑数据的顺序 const { top, left } = doSomething()

5.4、解构的默认值 解构变量时增加默认值,防止读到空值或者undefined
// bad const { a, b } = { a: 3 }// good const { a = 10, b = 1 } = { a: 3 }

6、类&构造函数
6.1、使用 class,避免直接操作 prototype ps:容易造成全局污染,造成冲突,定位bug不好定位。
// bad function Queue(contents = []) { this._queue = [..contents] } Queue.prototype.pop = function () { const value = https://www.it610.com/article/this._queue[0] this._queue.splice(0, 1) return value }// good class Queue { constructor(contents = []) { this._queue = [...contents] } pop() { const value = this._queue[0] this._queue.splice(0, 1) return value } }

6.2、使用 extends 来实现继承 ps优点:清晰,方便,并且这是一个不会破坏 instanceof 的内建实现原型式继承的方式
// bad const inherits = require('inherits') function PeekableQueue(contents) { Queue.apply(this, contents) } inherits(PeekableQueue, Queue) PeekableQueue.prototype.peek = function () { return this.queue[0] }// good class PeekableQueue extends Queue { peek () { return this.queue[0] } }

7、对象属性
7.1、优先使用 . 来访问对象属性 ps: 好处是简洁,方便
const joke = { name: 'haha', age: 28 } // bad const name = joke['name']// good const name = joke.name

7.2、当访问的属性是变量或者数字时只能使用 []
const luke = { jedi: true, age: 28, 12: 'num' } function getProp(prop) { return luke[prop] } const isJedi = getProp('jedi')

8、条件运算
8.1、使用 === 和 !== 而非 == 和 !=
const name = 'test'// bad if (name == 'test') { // ... }// good if (name === 'test') { // ... }

8.2、尽可能使用简洁的表达式
const name = ''// bad if (name === '') { // ...... }// good if (!name) { // ...... }

8.3、如果函数或全局中的 else 块后没有任何语句,可以删除 else
// bad function getName() { if (name) { return name; } else { return 'unnamed'; } }// good function getName() { if (name) { return name; } return 'unnamed'; }

9、eval() eval 方法比较 evil,所以我们约定禁止使用该方法
ps: eval会引起xss攻击;eval会干扰作用域链等等,不推荐在代码中使用eval
10、不要修改内置对象的原型
11、变量命名规则
11.1、常规变量用小驼峰格式
let userInfo = {}

11.2、全局常量用大写字母,多个字母以下划线连接
const MATH_PI = 3.14

11.3、类内的私有变量以下划线开头 11.4、类名以大驼峰格式
class UserInfo {}

11.5、普通函数名用小驼峰格式
function getUserInfo() {}

11.6、枚举变量用大驼峰格式,枚举属性 使用全部字母大写,单词间下划线分隔
const Week = { MONDAY: 0, TUESDAY: 1 }

11.7、boolean类型的变量建议使用 is或has开头 【建议】
// 常规变量 const loginStatus = 0 // 全局常量 const COUNT = 0 // 全局常量 const MAX_NUM = 99 // 类的声明 class Point { constructor(name, age) { this._name = name this._age = age } toString() { return '(' + this._name + ', ' + this._age + ')' } } // 普通函数 function stringFormat(source) { } // 枚举变量 const TargetState = { READING: 1, READED: 2, APPLIED: 3 } // boolean类型的变量 const isReady = false const hasSelected = false

12、&& 和 ||
二元布尔操作符是可短路的, 只有在必要时才会计算到最后一项。
// a++并不会执行 let x = false let a = 1 let y = x && a++

13、注释规范
13.1、单行注释 独占一行,// 后跟一个空格,缩进与下一行被注释说明的代码一致。
13.2、多行注释 尽量避免使用 /*.../ 这样的多行注释。有多行注释内容时,使用多个单行注释。
13.3、文档化注释格式 使用@key desc格式来书写
常用的关键词有:
@author 作者 @param 参数 @example 示例 @link 链接 @namespace 命名空间 @requires 依赖模块 @return 返回值 @version 版本号

注释的param的类型定义 都是以{ 开始, 以 } 结束
常用的param的类型:{String}, {Number}, {Boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}
13.4、函数/方法的注释 包含函数的说明,有参数和返回值时必须用注释标识
/** * @desc 函数描述 * @param {String} p1 参数1的说明 * @param {String} p2 参数2的说明 * @param {Number=} p3 参数3的说明(可选) * @return {Object} 返回值描述 */ function foo(p1, p2, p3) { return { p1: p1, p2: p2, p3: p3 } }

    推荐阅读