前端开发规范

3,373 阅读6分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

引言

作为一名合格的前端开发工程师,良好的代码编写规范是开发的前提,如下是常见的规范指南。

一:函数封装

  1. 永远记住一个函数只做一件事情
  2. 一个函数不超过20-30行代码,如果超过了必须考虑抽离代码。
  3. 如果封装的函数只出现一次,考虑封装成内联函数。

案例1

下面的函数包含了3部分,第一部分是日志的打印描述,同时它只会出现在该函数体中,因此将其抽离成内联函数。第二部分和第三部分分别代表订单的获取和统计可以单独的封装函数。

bad

    async function dealOrder(order) {
      console.log('查询订单列表')
      console.log('统计订单价格')
      console.log('信息完成')
      try{
        let orderInfos = await getOrderList(order.id)
        console.log('orderInfo detail',orderInfos)

        let total = orderInfos.reduce((sum,item)=>{
          return sum + item.price;
        },0)
        console.log('total price',total)
      }catch(e){
        console.error(e)
      }
    }

good

//获取订单列表
async function getOrderInfos(id) {
  let orderLists = await getOrderList(id)
  console.log('orderLists',orderLists)
  return orderLists
}


//统计订单信息
function accoutOrder(orderList) {
  let total = orderList.reduce((sum,item)=>{
    return sum + item.price;
  },0)
  console.log('total price',total)
}

//main
async function dealOrder(order) {
  orderTip()
  try{
    let orderList = await getOrderInfos(order.id) 
    accoutOrder(orderList)
  }catch(e){
    console.error(e)
  }

  function orderTip() {
    console.log('查询订单列表')
    console.log('统计订单价格')
    console.log('信息完成')
  }
}

二:函数参数最多2个,>=3使用对象接收

函数参数过多,很容易导致参数的传递错误,这时考虑使用对象将参数进行合并,在函数参数处直接使用对象解构。

案例

bad

function dealUserInfo(name,age,sex) {
  
}

dealUserInfo('dzp',22,1)

good

 function dealUserInfo({name,age,sex}) {

 }
dealUserInfo({name:'dzp',age:22,sex:1})

三:函数默认参数代替短路逻辑

bad

function test(name) {
  name = name || 'dzp'
}

good

function test(name='dzp') {
      
}

四:减少函数副作用

除非功能需要,否则函数的参数不要去修改其值。

五:多个if条件判断使用数组代替

当if判断条件>=3个时,无论在视觉还是维护上都十分难受,因此我们考虑借助数组进行优化设计

案例

bad

if(name==='dzp' || name==='xiao' || name==='ming') {

}

good

const names = ['dzp','xiao','ming']
if(names.includes(name)) {
    
}

六:async await必须捕获错误

错误的信息日志使用console.error更加显眼,便于调试发现错误。

案例

bad

  async function test() {
     let Infos = await getInfo()
     let details = await getDetails(Infos.id)
  }
  

good

  async function test() {
      try{
        let Infos = await getInfo()
        let details = await getDetails(Infos.id)
      }catch(e){
        console.error(e)
      }
   }

七:函数牢记提前退出

案例

这种写法大多数人肯定都有过,为什么不让程序提前判断不符合就结束?

bad

function test(name,age) {
  if(name) {
    if(age>22) {
      //do
    }
  }
}

good

function test(name,age) {
  if(!name || age<=22) return;
  //do
}

八:React中使用三元表达式代替 &&

案例

我们预期num是非0时输出指定的组件内容,但是react中数字0结合&条件时会在页面渲染数字0。因此提倡在jsx中多使用三元表达式而不是&

bad

 function App() {
  const [num,setNum] = useState(0)
  return (
    <div className="App">
      {num && <span>my content</span>}
    </div>
  );
}
export default App;

good

function App() {
  const [num,setNum] = useState(0)
  return (
    <div className="App">
      {num ? <span>my content</span> : ''}
    </div>
  );
}
export default App;

九:React中state过多时考虑使用对象合并

案例

多个state让代码变得臃肿难以维护,使用对象合并可以便捷的提高阅读性。

bad

function App() {
  const [age,setAge] = useState(0)
  const [name,setName] = useState('')
  const [info,setInfo] = useState('')

  const changeAge = () => {
    setAge(age+1)
  }
  const changeName = () => {
    setName('xiaoming')
  }
  const changeInfo = () => {
    setInfo('test')
  }
  return (
    <div className="App">
      <button onClick={()=>changeAge}>age</button>
      <button onClick={()=>changeName}>name</button>
      <button onClick={()=>changeInfo}>info</button>
    </div>
  );
}
export default App;

good

type peopleKey = 'age' | 'name' | 'info'
function App() {
  const [peopleInfo,setPeopleInfo] = useState({
    age:0,
    name:'',
    info:''
  })

  const changeInfo = (type:peopleKey,val:any) => {
    setPeopleInfo({
      ...peopleInfo,
      [type]:val
    })
  }
  return (
    <div className="App">
      <button onClick={()=>changeInfo('age',10)}>age</button>
      <button onClick={()=>changeInfo('name','dzp')}>name</button>
      <button onClick={()=>changeInfo('info','test')}>info</button>
    </div>
  );
}
export default App;

十:组件的props参数过多,必须得拆分组件

当组件的props数量过多时,不论在维护程度上还是在性能优化上的都是十分困难的。既然是组件化开发,我们应该尽可能让组件颗粒化。

bab

如下是一个描述人体部位的示例组件,我们传入了眼睛 嘴巴 胳膊 腿 脚作为参数。很明显这已经超过3个参数了,其中任意参数的更新都会导致整个组件的重新渲染,所以我们可以进一步封装,将人体部位组件尝试封装成上半身和下半身组件。

User.tsx

   import React,{useState} from "react"
    export default function User(props:any) {
      const { eye,mouth,arm,leg,foot } = props
      return (
        <div>
          <div>eye:{eye}</div>
          <div>mouth:{mouth}</div>
          <div>arm:{arm}</div>
          <div>leg:{leg}</div>
          <div>foot:{foot}</div>
        </div>
      )
    }

App.tsx

import React,{ReactNode, useState} from 'react';
import User from "./components/users/index"
function App() {
  const [eye,setEye] = useState()
  const [mouth,setMouth] = useState()
  const [arm,setArm] = useState()
  const [leg,setLeg] = useState()
  const [foot,setFoot] = useState()
  //眼睛 嘴巴 胳膊 腿 脚
  return (
    <div className="App">
      <User eye={eye} mouth={mouth} arm={arm} leg={leg} foot={foot} />
    </div>
  );
}
export default App;

good

我们将身体拆分成两个组件,头部组件和身体组件

Hedaer.tsx

import React,{useState} from "react"
export default function Header(props:any) {
  const { eye,mouth } = props
  return (
    <div>
      <div>eye:{eye}</div>
      <div>mouth:{mouth}</div>
    </div>
  )
}

Body.tsx

import React,{useState} from "react"
export default function Body(props:any) {
  const { arm,leg,foot } = props
  return (
    <div>
      <div>arm:{arm}</div>
      <div>leg:{leg}</div>
      <div>foot:{foot}</div>
    </div>
  )
}

App.tsx

import React,{ReactNode, useState} from 'react';
import Header from "./components/users/index"
import Body from "./components/users/body"
function App() {
  const [eye,setEye] = useState()
  const [mouth,setMouth] = useState()
  const [arm,setArm] = useState()
  const [leg,setLeg] = useState()
  const [foot,setFoot] = useState()
  return (
    <div className="App">
      <Header eye={eye} mouth={mouth}></Header>
      <Body arm={arm} leg={leg} foot={foot} ></Body>
    </div>
  );
}

export default App;

十一:使用封装减少UI耦合

在实际开发中会经常出现UI耦合的情况,如果耦合次数大于等于3时(同时结合复杂度考虑)就必须通过封装将它们进行统一管理。

bab

下面这个例子中表单项出现了多次耦合,如果表单项过多那代码将会出现大量耦合,此时十分不利于维护和阅读,因此考虑通过封装将他们进行处理,大大提高了代码阅读和拓展能力。

import React,{ReactNode, useState} from 'react';
function App() {
  const [username,setUsername] = useState('1')
  const [password,setPassword] = useState('2')
  const [desc,setDesc] = useState('3')
  const [other,setOther] = useState('4')
  return (
    <div className="App">

      <div className='form-item'>
        <input type="text" name='username' value={username} />
      </div>

      <div className='form-item'>
        <input type="text" name='password' value={password}/>
      </div>

      <div className='form-item'>
        <textarea name='desc'value={desc} />
      </div>

      <div className='form-item'>
        <input type="text" name='other' value={other} />
      </div>
    </div>
  );
}

export default App;

good

import React,{ReactNode, useState} from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
  const [username,setUsername] = useState('1')
  const [password,setPassword] = useState('2')
  const [desc,setDesc] = useState('3')
  const [other,setOther] = useState('4')
  const userInfo = [
    {formKey:'input',name:'username',val:username},
    {formKey:'input',name:'password',val:password},
    {formKey:'textarea',name:'desc',val:desc},
    {formKey:'input',name:'other',val:other},
  ]
  const formatFormItem = (e:any):ReactNode => {
    return (
      <div className='form-item'>
        {
          e.formKey==='input' ? 
          <input name={e.name} value={e.val}></input> : 
          <textarea name={e.name} value={e.val}></textarea>
        }
      </div>
    )
  }
  return (
    <div className="App">
      {userInfo.map(item=>formatFormItem(item))}
    </div>
  );
}

export default App;

十二:组件的多个状态使用枚举定义

枚举的好处就是见名知意,在开发中我们为了省事,经常定义一些匪夷所思的状态去展示不同的逻辑代码。 从今天起必须牢记多种状态,能用枚举就用枚举。

bad

如下是根据用户状态码渲染用户展示信息的逻辑代码,这种代码看起来很让人难受,开发者必须保证状态码和当前状态对应上,否则极容易出错。这就是糟糕的写法,sad。

import React from 'react';
function App() {
  const renderStatue = (statue:number=1001) => {
    switch(statue) {
      case 1001:
        return <span>访客模式</span>
      case 1002:
        return <span>未登录模式</span>
      case 1003:
        return <span>登录模式</span>
      case 1004:
        return <span>退出模式</span>
      default: return <></>
    }
  }
  return (
    <div className="App">
      {renderStatue(1001)}
    </div>
  );
}

export default App;

good

通过引入枚举定义状态,开发者很容易根据枚举含义站到对应的状态码,提高了代码的阅读性和拓展能力。

import React from 'react';
enum UserStatue {
  VISITOR=1001,
  NOTLOGIN=1002,
  LOGIN=1003,
  EXIT=1004
}
function App() {
  const renderStatue = (statue:number=1001) => {
    switch(statue) {
      case UserStatue.VISITOR:
        return <span>访客模式</span>
      case UserStatue.NOTLOGIN:
        return <span>未登录模式</span>
      case UserStatue.LOGIN:
        return <span>登录模式</span>
      case UserStatue.EXIT:
        return <span>退出模式</span>
      default: return <></>
    }
  }
  return (
    <div className="App">
      {renderStatue(1001)}
    </div>
  );
}

export default App;

总结

如果文章对您有帮助,点点赞,点点关注支持下我哎,我们一起进步!