編寫更優雅的 JavaScript 代碼

簡單總結下寫代碼過程的想法react

代碼技巧

  1. ES2015+ 新特性寫法

熟練使用 ES6 新特性能夠優化代碼,更加簡潔,代碼對比webpack

// 箭頭函數
function foo(){
  console.log('hello world')
}

const foo = () => console.log('hello world')

// 數組去重
const formatArray = arr => [...new Set(arr)]

// 數組合並
const newArr = [...arr1, ...arr2, 'value']

// 建立數組
a = [...Array(4).keys()]  // [0, 1, 2, 3]

// 對象淺拷貝
const newObj = {...obj}

// 解構賦值
const person = {name: 'bao', age: 18}
const { name, age } = person

// 常見對象屬性取值前判斷對象是否存在
// 以下是 react + antd 渲染 table 的簡單代碼,對象存在性判斷 + 默認值設置

render(){
  const { downloadList } = this.props.store.downloadList
  let items = downloadList && downloadList.items || []
  let itemCount = downloadList && downloadList.itemCount || 10
  
  return <Table dataSource={items} pagination={{total: itemCount}} />
}

// 優化後
render(){
  const { items, itemCount } = this.props.manageStore.downloadList || {}
  return <Table dataSource={items || []} pagination={{total: itemCount || 10}}/>
}
...
複製代碼
  1. 優化邏輯判斷語句

大量的 if else 邏輯判斷難以維護,且性能較差,可用多種方式代替git

// 對象配置法
// ps 函數內部有條件判斷,且 return 值時,知足條件當即return,而不要在結尾return
const foo = v => {
  if (v === 'name') {
    return 'bao'
  } else if (v === 'age') {
    return '18'
  } else if (v === 'height') {
    return '180'
  }
}

const cfg = {
  name: 'bao',
  age: '18',
  height: '180'
}

const foo = v => cfg[v]

// 數組配置法
if (value === 'hello' || value === 'world' || value === 'blabla') {
  // ...
}

// 配置數組形式
const rightValue = ['hello', 'world', 'blabla']
if (rightValue.includes[value]) {
  // ...
}
複製代碼
  1. && 、 || 和 三元運算
if (name === 'bao') {
  someFunc()
}

name === 'bao' && someFunc()

if (name === 'bao') {
  someFunc()
} else {
  elseFunc()
}

name === 'bao' ? someFunc() : elseFunc()
複製代碼

堅定反對多個三元運算相連使用,可讀性太差以下示例github

let example = ''
if(type == 1) {
    example = 'a'
} else if (type == 2) {
    example = 'b'
} else if (type == 3) {
    example = 'c'
}else{
    example = 'd'
}

// 改三元運算
example = type == 1 ? 'a' : type == 2 ? 'b' : type == 3 ? 'c' : 'd'

// 這樣的一堆 ?和 : ,實際項目中代碼複雜時可讀性太差
// 優化:
const typeCfg = {
    1: 'a',
    2: 'b',
    3: 'c',
    default: 'd'
}
let example = typeCfg[type] || typeCfg.default;
複製代碼
  1. 對象屬性變量應用

如在 react 中,調用 action 方法來獲取數據,不一樣條件執行不一樣方法web

if (isMember) {
  let res = await actions.getMemberInfo(params)
} else {
  let res = await actions.getCommonUserInfo(params)
}

const actionName = isMember ? 'getMemberInfo' : 'getCommonUserInfo'
let res = await actions[actionName](params)
複製代碼
  1. 類型轉換
// 字符串轉數字
let str = '1234'
let num = +str

console.log(+new Date()) // 1536231682006

// 轉字符串
let str = `${num}`
let str2 = num + ''
複製代碼
  1. 用 Array.map(), Array.filter() 代替數組 for 循環實現簡易寫法

以下對數組元素的操做json

let arr = [1, 2, 3, 4, 'A', 'B']

// 1. 取出 arr 中數字項爲新數組
let numArr = []
for(let i in arr){
  if(typeof arr[i] === 'number'){
    numArr.push(arr[i])
  }
}

// 改用filter
let numArr2 = arr.filter(item => typeof item === 'number')
console.log(numArr2) // [1,2,3,4]

// 2. 得到新數組,元素是 arr 每一個元素做爲 value, key 爲 arr 下標的對象, 不修改 arr
let strArr = []
for(let i in arr){
  strArr.push({[i]: arr[i]})
}

// 改用 map
let strArr2 = arr.map((item, i) => ({[i]: arr[i]}))
console.log(strArr2) // [ { '0': 1 },{ '1': 2 },{ '2': 3 }, { '3': 4 }, { '4': 'A' }, { '5': 'B' } ]
複製代碼

七、淺拷貝、深拷貝 複雜數據類型對象深拷貝建議使用庫來實現,如 lodash.cloneDeep數組

// 淺拷貝
let obj1 = { a: 11, b: { ba: 22 } }
let obj2 = {...obj1}
console.log(obj2); // ​​​​​{ a: 11, b: { ba: 22 } }​​​​​

console.log(obj1 === obj2); // false
console.log(obj2.b === obj1.b); // true

// 深拷貝,這種方法須要對象可以被 json 序列化
let obj3 = JSON.parse(JSON.stringify(obj1))
console.log(obj3); //  ​​​​​{ a: 11, b: { ba: 22 } }​​​​​
console.log(obj3 === obj1); // false
console.log(obj3.b === obj1.b); // true
複製代碼
  1. optional-chaining ?. 代替對象是否存在判斷,提升代碼健壯性

須要添加 @babel/plugin-proposal-optional-chaining 插件支持, 可參考babel 7 簡單升級指南, 最喜歡這個語法,babel7 升級第一時間試用緩存

// obj?.prop       // optional static property access
// obj?.[expr]     // optional dynamic property access
// func?.(...args) // optional function or method call

// 以下代碼
let { data } = this.props
let list = data && data.tableData && data.tableData.list || []

// 使用 ?.
let list = data?.tableData?.list || []
複製代碼

更高效的代碼

  1. 使用局部變量代替引用類型查找

局部變量的讀取速度最快,而引用類型的數據讀取須要按引用指針去查找,因此能夠對屢次使用的引用類型屬性 使用局部變量讀取一次,重複使用bash

let obj = {
  person: {
    man: {
      bao: {
        age: 18
      }
    }
  }
}

let age = obj.person.man.bao.age
// use age do many things
複製代碼
  1. 刪除多個對象屬性時先使屬性爲 null

刪除屬性時,js 引擎會去查找該屬性的值是不是其餘對象的引用,因此刪除前提早賦值爲 null,能夠減小 js 引擎的檢測過程,提升效率,不過,8102 年的 V8 真的須要這些優化麼。。。babel

let obj = {
  person: {
    man: {
      bao: {
        age: 18
      }
    }
  }
}
obj.person = null
delete obj.person
複製代碼
  1. 局部變量保存數組 length

關於這個問題討論一直很多,參考有沒有必要緩存JavaScript數組的length

let len = arr.length
for(let i=0; i<len; i++)){
  // ...
}
複製代碼

代碼結構組織等優化

隨着項目的日益擴大,代碼量快速增多,後期維護很是耗費時間,主要經過如下方法減小代碼量

  1. 凡是二次出現的代碼片斷,邏輯組件,當即考慮複用,拆分公共組件,漸進加強,逐漸完善功能

  2. 封裝功能函數,儘可能使函數單一職責,重複功能函數創建項目函數庫

  3. 善用 class 類的繼承,複用功能方法

    如將 fetch 請求的 get/post 方法定義到 CommonActions class, 而後建立 actions 時只須要 extends CommonActions 就能夠在新的 actions 中直接調用 this.get()/this.post() 來完成 請求數據。

    總之,在邏輯清晰的狀況下,儘量複用組件、方法,維護好高質量的公共組件、方法,便於項目維護和偷懶

  4. 善用裝飾器

    react 高階函數已經提供了一種優雅的組件複用形式,而裝飾器的使用能夠更優雅地實現高階函數

    同時,如ant design Form 組件的建立也可用裝飾器更簡單的實現

    class MyForm extends React.Component {
    // ...
    }
    
    const WrapForm = Form.create()(MyForm)
    
    // 裝飾器形式
    @Form.create()
    class MyForm extends React.Component {
    // ...
    }
    複製代碼

更新:20190407

  1. 語義化命名

    • 給每一個函數和 class 組件添加明確的語義化命名。 匿名函數、組件寫起來方便,可是一旦出現 bug 難以在錯誤信息的調用棧中快速定位到報錯函數和組件
    • 語義化變量名或函數名。 不用擔憂變量名太長webpack 會搞定這些,咱們更須要經過變量名或函數名直觀的瞭解變量或函數的功能、做用, 提升代碼閱讀效率和可維護性,讓 3 個月後的本身和同事可以更快看懂代碼。
  2. 常量、配置項與業務邏輯解耦

    • 全部固定的常量或配置項以獨立模塊(如 constant.js) 的形式集中配置,方便複用和維護
    • 常量命名使用大寫字母也是區分常量和普通變量的好辦法
    • 若是獨立保存了常量和配置項,那和同事約定相關文件存儲結構也頗有必要
  3. 儘量完善的註釋

    • 語義化的命名習慣足矣代替不少註釋
    • 公共組件或函數詳細寫清楚 props 參數或函數參數註釋和使用狀況,哪些是必須,哪些可選, 儘可能使用標準註釋格式(如 (JSDoc)[github.com/jsdoc3/jsdo…],方便你們使用和參考
相關文章
相關標籤/搜索