如何優雅地書寫JavaScript

這篇文章包含了幾乎全部關於提升代碼質量的內容,尤爲是在構建大型應用程序時。vue

主要包括四個部分:react

  • 基本原則
  • 保持整潔
  • 保持擴展性
  • 抽象化
本主題僅涉及原生js,關於框架(好比react和vue)的內容會在之後的文章中展示。

基本原則

我想大家大多數人以前都據說過SOLID,也就是面向對象設計裏的SOLID原則。面試

這些原則基於面向對象設計,因此可能不適合其餘編程範式。即使如此,它也涵蓋了大多數狀況。編程

例如,SOD既能夠應用於面向對象編程,也能夠應用於函數式編程。api

單一責任原則(SRP)

開放封閉原則(OCP)

里氏替換原則(LSP)

接口分離原則(ISP)

依賴倒置原則(DIP)

保持整潔

變量

變量或許是在開發過程當中最多見的術語。promise

命名

  • 使用語義明確的命名
// 不推薦
// 我不知道這個變量表明什麼意義
const flag = true;

// 推薦
const downloaded = true;
const enabled = true;
  • 使用可讀的命名
// 不推薦
// 也是沒有意義
const yyyyMMdd;

// 推薦
const today;
  • 使用語義一致的詞彙
// 不推薦

// file1
function getUserData()
// file2
function fetchUserData()
// file3
function getUserRecord()
// file4
function getUserInfo()

// 推薦

// file1
function getUserInfo()
// file2
function getUserInfo()
// file3
function getUserInfo()
// file4
function getUserInfo()
  • 使用可搜索的命名
// 不推薦
for(let i=0;i<5;i++) {
 // ...
}

// 推薦
const COUNT = 5;
for(let i=0;i<COUNT;i++) {
 // ...
}
  • 使用自解釋的命名
// 不推薦
if (!group) {
  return pictureCollect.list;
}
return getListByGroup(group, pictureCollect.list);

// 推薦
const getAllList = list => list;
// const getAllList = R.identity(list)
if (!group) {
  return getAllList(pictureCollect.list);
}
return getListByGroup(group, pictureCollect.list);
  • 避免冗餘的命名
// 不推薦
const phone = {
 phoneOwner: 'lucifer',
 phoneSize: ''
}

// 推薦
const phone = {
 owner: 'lucifer',
 size: ''
}
  • 好代碼,不撒謊
程序從不說謊,但註釋(也包括名稱)可能會。

類型

  • 推薦使用 const

控制流

  • 使用promise方法而不是callback(回調函數)
異步/等待也是很是強大的。

分支

  • 使用短路表達式或默認值
// 不推薦
function downloadFile({_filename, _encoding}) {
   let filename = 'untitled.txt';
   let encoding = 'utf-8'
   if (filename) {
    filename = _filename;
   }
   if (encoding) {
    encoding = _encoding;
   }
   // ....
}

// 推薦
function downloadFile({filename = 'untitled.txt', _encoding}) {
   const encoding = _encoding || 'utf-8';
   // ....
}
  • 使用策略或多態性(開放封閉原則)
  • 使用責任鏈(開放封閉原則)
  • 將其分解成不一樣的功能(單一責任原則)
  • 封裝條件
// 不推薦
if (number === 0 && (1 / number) === -Infinity)
// 推薦
function isNegativeZero(number) {
   return number === 0 && (1 / number) === -Infinity
}

if (isNegativeZero(number))
  • 避免沒必要要的條件

表達

  • 使用迭代器而不是循環
在特定環境下遞歸表現的更好。

函數

參數儘可能要少

使用純函數

相比於命令式,函數式更好

當心在全局做用域中的函數(包括在他們原型對象上的方法)

one level of abstraction

只作一件事情(單一責任原則)

write less

調用者和被調用者位置應該儘可能接近

報錯

  • 永遠不要對報錯不作處理
// 不推薦
const logger = console.log.bind(console)
fetch('http://www.test.com')
 .then(notifyUser)
 .catch(logger)
 
// 推薦

fetch('http://www.test.com')
 .then(notifyUser)
 .catch(err => {
  // 你能夠全作,也能夠選一個
  console.error(err)
  notifyUser(err)
  sendErrToServer(err)
 })
打印、存儲、通知用戶或將其發送到遠程服務器

測試

  • 一步一測試

格式

  • 美觀
  • 一致

註釋

  • 註釋讓人難以理解的關鍵部分
  • 刪除註釋代碼
  • 註釋必要的信息
create, ltime etc
  • 避免繪圖註釋
  • 根據代碼意義註釋,不要說謊
  • 註釋應與相關代碼位置一致
  • 相比於註釋,一個語義明確的命名更好
// 不推薦
// means the date of the today
const yyyyMMdd;

// 推薦
const today;

保持擴展性

加強

好萊塢原則

我一直很欣賞好萊塢原則這個名稱的巧妙。這個原則的本質是「不要給我打電話,我會打給你」。如你所知,這是你在面試好萊塢電影裏的一個角色後可能聽到的答覆。而軟件世界裏的好萊塢原則也是同樣的觀念。其目的是注意要聰明的構造和實現你的依賴關係。服務器

例如:app

import a from '../../a.js'
import b from '../../../b.js'
import a from '../c.js'

function app() {
   return {
    start() {
     a.start();
     b.start();
     c.start();
     console.log('app stared~')
    }
   }
}

咱們編寫的代碼直接依賴於a、b和c。當它們中的任何一個改變它的api或位置時,你必須跟着變更代碼。框架

var { decorator } = require("./decorator.public.js");

function app({a, b, c}) {
   return {
    start() {
     console.log('app stared~')
    }
   }
}

// enhance
// = IOC + decorator
decorator(app);

if we use enhance, which implemented by IoC and decorator.
若是咱們使用經過Ioc和裝飾器實現的加強技術,
可使得應用程序易於測試和擴展。.less

裝飾器可能就像這樣:

// 爲了簡單的目的
import a from '../../a.js'
import b from '../../../b.js'
import a from '../c.js'

function decorator(app) {
 return app({a, b, c})
}

這很簡單,但徹底不一樣。

  • app的參數道出了真相
  • 從依賴項中解耦

並且咱們能夠改變app的行爲.

function a() {console.log('a')}
var _a = a;
a = function() {
 _a();
 console.log('hello decorator')
}
a();
// a
// hello decorator

更優雅的方式:

function a() {console.log('a')}
function dec() {onsole.log('hello decorator')}

compose(dec, a)

抽象化

軟件開發的關鍵是找出變量和變量。

而後對不變部分進行編程,使變量的影響在它的控制之下。

也稱爲抽象編程.

對比傳統的面向對象編程(OOP)來講,函數式編程(FP)更優越。
藉助「無數據樣式」(即「pointfree」)的幫助,您能夠將細節與邏輯分離開來。
因此你能夠單獨留下細節,讓邏輯變得純粹。

我想再強調一點,那就是人們有時會說,沒有抽象概念總比錯誤的抽象好。這實際上意味着錯誤抽象的代價很是高,因此要當心。我認爲這有時會被誤解。這並不意味着您應該沒有抽象概念。 這隻意味着你必須很是當心。 -- Malte Ubl在JSConf澳大利亞演講。

咱們必須善於發現正確的抽象。

只有這樣,您才能編寫可重用的、可管理的和可擴展的代碼。

相關文章
相關標籤/搜索