前端代码规范

一 业务开发和日常编写

此类规范从日常开发中总结,使用频率较高, 不断更新中

1、避免魔法变量和硬编码

// 魔法变量
//bad
if(a == 1) {
    //do something
}
if(b == 2 && c == 3) {
    //do something
}

//good => 提取公共变量到配置文件(也可以使用map),大写提取(这里省略)
const STATUS_CONFIG = {
 IS_VIP: 1,
 IS_LOGIN: 2,
 IS_BIND: 3
}
if(STATUS_CONFIG.IS_VIP) {
    //do something
}
if(STATUS_CONFIG.IS_LOGIN && STATUS_CONFIG.IS_BIND ) {
    //do something
}

//硬编码
//bad 硬编码存在于两个方法域模块中
const funa = (reqs) => {
    const token = reqs.hearders.get('auth')
    if(token) {
        localStorage.setItem('authToken',token)
    }
}
const funb = () => {
    const token = localStorage.getItem('authToken')
}

//good 提取到环境变量或者配置文件
const AUTO_TOKEN = 'AUTH_TOKEN'

const funa = (reqs) => {
    const token = reqs.hearders.get('auth')
    if(token) {
        localStorage.setItem(AUTO_TOKEN,token)
    }
}
const funb = () => {
    const token = localStorage.getItem(AUTO_TOKEN)
}

2、避免多参数传递

//bad
const funb = (a, b, c, d, e) => {
    //...
}
funb('name',100,20,'type',2)

//good 对象封装和解构
const funb = (obj) => {
    const {a, b, c, ...others} = obj
    //...
}
funb(obj)

3、避免多条件判断重复使用

//bad 魔法变量参考问题1
const fun = () => {
    if(a == 1 && !b && d == 2 || c == 3) {
        //...
    }
}
if(a == 1 && !b && d == 2 || c == 3) {
    //...
}

//good
const IS_BIND = () => {
    return !!(a == 1 && !b && d == 2 || c == 3)
}
//or
// const IS_BIND = !!(a == 1 && !b && d == 2 || c == 3)
const fun = () => {
    if(IS_BIND()) {
        //...
    }
}
if(IS_BIND()) {
    //...
}

4、 避免多类似条件if/else

//  if/else 未优化之前

/**
 * 按钮点击事件
 * @param { string } type 
 */

const onPageClick = (type) => {
  if (type === "1") {
    showLog("a");
    jumpTo("pageA");
  } else if (type === "2") {
    showLog("b");
    jumpTo("pageB");
  } else if (type === "3") {
    showLog("c");
    jumpTo("pageC");
  } else if (type === "4") {
    showLog("d");
    jumpTo("pageD");
  } else if (type === "5") {
    showLog("e");
    jumpTo("pageE");
  } else {
    showLog("f");
    jumpTo("defaultF");
  }
}

// key/value结构优化

// 除了使用object也可以使用 map 来进行优化(map的优势请自行查阅
const actions = {
  1: ["a", "pageA"],
  2: ["b", "pageB"],
  3: ["c", "pageC"],
  4: ["d", "pageD"],
  5: ["e", "pageE"],
  default: ["f", "defaultF"],
};

/**
 * 按钮点击事件
 * @param { string } type
 */
function onPageClick(type) {
  let action = actions[type] || actions["default"];
  // 打印日志
  showLog(action[0]);
  // 跳转页面
  jumpTo(action[1]);
}

建议不要使用switch进行优化

  • 代码更加臃肿不便于扩展和进一步优化

  • break使用不当造成判断步骤问题

 5、避免嵌套地狱

//bad
funa().then(a => {
  funb(a).then(b => {
    func(b).then(c => {
        doSomthing(c)
    })
  })
})
//recommend
funa().then(funb).then(func).then(c => doSomething).catch(err => console.err(err))

6、避免一条路走到黑

// -----------------------------------------------------------------优化前

需求:条件 1 已经绑定手机号 && 2 已经关注公众号 && 3 领取礼品
对应方法:绑定:isBind/funDoBind 关注 isLike/funDoLike 领取礼品 getGift

const checkActivity = () => {
    if (isBind) {//如果已绑定
        if (isLike) {//如果已关注
          //则领取礼品
          getGift();
        } else {//如果未关注
            //去关注
            funDoLike(() => {
                //关注成功的回调
                getGift();
            });
        }
    } else {//如果未绑定,去绑定
        funDoBind(() => {
            if (isLike) {//如果已关注
              //则领取礼品
              getGift();
            } else {//如果未关注
                //去关注
                funDoLike(() => {
                    //关注成功的回调
                    getGift();
                });
            }
        });
    }
}
// --------------------------------------------------------优化后
以时间换空间:不满足直接返回再走一遍
const checkActivity = () => {
  if(isBind && isLike) return getGift();
  if(!isBind) {
    funDoBind(() => {
      return checkActivity()
    })
  }

  if(!isLike) {
    funDoLike(() => {
      return checkActivity()
    })
  }
}

二、代码规范(js)

1、变量声明

所有声明必须严格执行const, let,不允许使用var(如果不是必要请使用const,因为在ts中字符串泛型let会出错

2、保留字

JavaScript
// bad
const a = {
  default: {},  // default 是保留字
  common: {}
}

// good
const a = {
  defaults: {},
  common: {}
}

3、引号问题

对字符串使用单引号,尽量不适用双引号

1一致性:可以在字符串内部使用另一种引号

2避免转义字符:双引号中包含双引号字符串

3与HTML结合使用:const htmlString = '<div class="container">This is an HTML element.</div>'

// bad
const a = "123"

// good
const a = '123'

 4、链式复制

变量不要进行链式赋值,变量链式赋值会创建隐藏的全局变量(除非你懂得具体含义)

//----------------案例
// bad 
let a = b = 2

// good
let a = 2
let b = 2

//--------------说明
1 变量覆盖:当你在链式赋值中使用相同的变量名时,后续的赋值会覆盖前面的赋值。这可能导致你意外地丢失数据。

let a = b = c = 10;
// 等同于 c = 10; b = 10; let a = b;
//如果忘记使用let和const会造成多个全局变量污染

2 对象引用:如果你在链式赋值中操作对象属性或数组元素,并且其中一个属性是一个对象引用,那么后续的赋值可能会影响前面的属性,因为它们都引用了同一个对象。

const obj = { prop: 1 };
const a = obj.b = obj.prop = 2;
//在这个例子中,a、obj.b 和 obj.prop 都将成为 2,因为它们引用了同一个对象。

5、避免多余变量的声明

6、创建对象

通常,字面量声明和构造函数声明都有各自的用途。推荐根据对象的复杂程度和功能需求来选择合适的声明方式
对于简单的、静态的数据对象,字面量声明更直观、简洁

const person = {
  name: "Alice",
  age: 30,
  job: "Developer"
};

对于需要具有自定义方法和行为的对象,构造函数声明更适用

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}

const person = new Person("Alice", 30, "Developer");

7、字符串拼接(尽量使用模板字符)

/ bad
const str = 'a' + 'b' + test

// good
const str = `ab${test}`

8、当你必须使用函数表达式(比如传递匿名函数)时,使用箭头函数标记

它将创建在 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
})

9、解构赋值

解构可以避免创建属性的临时引用

对象解构
// bad
function getFullName(user) {
  const firstName = user.firstName
  const lastName = user.lastName
  return `${firstName} ${lastName}`
}

// good
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`
}
数组结构
const arr = [1, 2, 3, 4]

// bad
const first = arr[0]
const second = arr[1]

// good
const [first, second] = arr
函数回传参数解构
/** 
函数需要回传多个值时,请使用对象的解构,而不是数组的解构。 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()
解构默认值
// bad
const { a, b } = { a: 3 }

// good
const { a = 10, b = 1 } = { a: 3 }

10、使用 === 和 !== 而非 == 和 !=

除非你懂得为何去使用

11、尽可能使用简介表达式

const name = ''

// bad
if (name === '') {
    // ......
}

// good
if (!name) {
    // ......
}

三目运算

const name = getName()??'-'

12、如果函数或全局中的 else 块后没有任何语句,可以删除 else

// bad
function getName() {
    if (name) {
       return name;
    } else {
       return 'unnamed';
    }
}

// good
function getName() {
    if (name) {
       return name;
    }
    return 'unnamed';
}

13、尽量不要使用eval

eval会引起xss攻击;eval会干扰作用域链等等,不推荐在代码中使用eval

14、变量命名

1 常规小驼峰

let userInfo = {}

2 全局常量用大写字母,多个字母以下划线连接

const MATH_PI = 3.14

3 类名、组件名以大驼峰格式开头
4 枚举变量用大驼峰格式,枚举属性 使用全部字母大写,单词间下划线分隔

const Week = {
  MONDAY: 0,
  TUESDAY_TYPE: 1
}

15、boolean类型的变量建议使用 is或has开头

16、单行和多行注释(根据函数复杂度自行定义

17、永远不要直接使用 undefined 进行变量判断;使用 typeof 和字符串’undefined’对变量进行判断。

防止变量未声明的错误:如果你尝试访问一个未声明的变量,直接与 undefined 比较会导致引用错误(ReferenceError)。但是,使用 typeof 检查不会引发错误,它会返回字符串 "undefined",从而避免了异常。

//bad:如果person未定义 这会引发 ReferenceError
if (person === undefined) { ... }
//good
if (typeof person === 'undefined') { ... }

 避免全局变量冲突:直接比较 undefined 可能会导致全局变量的冲突。如果某个变量名在当前作用域中没有被声明,JavaScript 将尝试在全局作用域中查找该变量。这可能导致意外的行为。

// 在全局作用域中有一个未声明的变量 person
if (person == undefined) {
  // 这里的条件将通过,但可能不是你期望的结果
}

 类型安全: 使用 typeof 进行比较可以确保变量的类型与预期的类型匹配。直接与 undefined 比较可能会出现类型转换问题,因为 JavaScript 中的类型转换规则可能会使得一些非预期的结果

// 变量 person 是字符串 "undefined"
var person = "undefined";

if (person == undefined) {
  // 这里的条件通过,但可能不是你期望的结果
}

if (typeof person == "undefined") {
  // 这里的条件不通过,因为变量 person 的类型不是 "undefined"
}

 18、条件判断和循环最多三层

条件判断能使用三目运算的尽量使用三目运算;谨记不要写太长的三目运算

// not recommended
if(a) {
  return 'conditionA'
} else {
  return 'conditionB'
}

//recommended
return a?'conditionA':'conditionB'

如果超过3层请抽离成函数

// not recommended
return a?b?'conditionA':'conditionB':'conditionDefault'

//recommended
const checkConditionB = (a, b) => {
  if(a) return b?'conditionA':'conditionB'
  return 'conditionDefault'
}

三 代码规范(css)

1、尽量按照less和sass的格式进行书写

其中包括但不限于:变量提取、嵌套复用等等方式

2、简写

/* bad */
.geely {
   padding-left: 15px;
   padding-top: 20px;
   padding-bottom: 20px;
   padding-right: 15px;
}
/* good */
.geely {
   padding: 20px 15px;
}

3、尽量不使用 !important 声明

4、嵌套层级(建议不超过3级)

5、可复用变量

/* bad */ 
.geely {
   color: #fff;
   border-color: #fff;
}

/* good */
$color: #fff;
.geely {
   color: $color;
   border-color: $color;
}

/*.less写法*/

  /* bad */
.geely {
   width: 100px;
}
.hwl {
   width: 100px;
}

/* good */ 
@width: 10px;
.geely {
   width: @width;
}
.hwl {
   width: @width;
}

6、善用mixin

/* bad */
.geely-text {
   display: inline-block;
   white-space: nowrap;
   width: 100%;
   overflow: hidden;
   text-overflow: ellipsis;
}
.geely-msg {
   display: inline-block;
   white-space: nowrap;
   width: 100%;
   overflow: hidden;
   text-overflow: ellipsis;
}

/* good 抽离成mixin来调用*/
@mixin text-overflow() {
   display: inline-block;
   white-space: nowrap;
   width: 100%;
   overflow: hidden;
   text-overflow: ellipsis;
}
.geely-text {
   @include text-overflow();
}
.geely-msg {
   @include text-overflow();
}

7、运算规范

/* bad */
.geely {
   width: calc(100%-100px);
}
/* good */
.geely {
   width: calc(100% - 100px);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值