在咱們開始這個題目的時候,咱們應該思考下面幾個問題:css
why?
html
前端還在 刀耕火種的時代的時候,前端是沒有 工程
這個概念的。更可能是切圖仔
這個概念,(將設計師設計出來的 web 、app、h5 的 UI
經過 PS 切圖
而後再經過 HTML、CSS 實現出來)的這麼一個工種。那麼隨着 互聯網興起到後來的移動互聯網發展,To C 產品需求 精細化, 用戶對於 C 端產品愈來愈挑剔也促使着 前端工程化愈來愈規範化了。 漸漸的前端工程
造成,那麼隨之而來的就是 工程化 帶來的 規範化
。前端
回到 why
的問題上來,咱們先舉一個簡單的例子來講,vue
可能 工程化 這個名詞在不少的後端語言中早早的就已經造成了,但前端 這麼一門到如今大學課程都沒開課的工種,全靠大學畢業後工做中自學積累而來,那麼咱們是否能夠說,現階段前端搞的好的人,Ta 的自學能力必定不會差。java
what?
node
什麼是前端開發規範?react
HTML\CSS\Javascript\TypeScript 的代碼編寫規範,這裏咱們着重講一下 JS 的 編碼規範webpack
javascript 的數據類型
git
1.1 基本數據類型
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
1.2 引用數據類型
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
以上則 是 基礎數據 在 coding
的時候的基本規範。
變量、常量、定義規範
prefer-const
, no-const-assign
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
建議使用 const 定義常量,能夠阻止一些 重複定義致使的 bug
no-var
// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
推薦使用 let 來定義變量,造成塊級做用域,減小由於變量提高致使的bug
對象 定義規範
no-new-object
// bad const item = new Object(); // good const item = {};
推薦使用 對象字面量來定義空對象,而不是經過 new 實例化進行操做
// bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
object-shorthand
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, addValue(value) { return atom.value + value; }, };
推薦 在給對象添加方法的時候,使用 簡化符號
object-shorthand
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
方法名若是和對象的屬性名稱相同的時候,推薦使用簡化符號編寫
object-shorthand
的時候,推薦先寫出簡化符號的屬性或者方法const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { episodeOne: 1, lukeSkywalker, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, };
quote-props: as-needed
// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };
推薦在 給對象屬性不要輕易加引號,除非必要的狀況下,好比屬性的key帶有 符號等
no-prototype-builtins
不使用 prototype 的內置命令// bad console.log(object.hasOwnProperty(key)); // good console.log(Object.prototype.hasOwnProperty.call(object, key)); // best const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope. /* or */ import has from 'has'; // https://www.npmjs.com/package/has // ... console.log(has.call(object, key));
推薦理由是:這些方法可能被有關對象上的屬性所遮蔽
Object.assign
好// very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ delete copy.a; // so does this // bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // good const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
推薦緣由就是, 對象擴展符 比 Object.assign 看着舒服10倍吧
no-array-constructor
/*推薦使用經過字面量建立對象、數組*/ // bad const items = new Array(); // good const items = [];
Array#push
/*推薦使用 push 來進行 stack add */ // bad someArr[someArr.length] = 'xxxxsssswwww' // good someArr.push('xxxxsssswwww')
/*推薦使用 `...` 進行數組 複製 */ // bad for(i=0; i<arr.length; i++) { newArr[i] = arr[i] } // good let newArr = [...arr]
/*推薦使用 `...` 將可迭代對象轉換爲數組 */ // bad const foo = document.querySelectorAll('.foo'); nodes = Array.from(foo) // array[] // good let nodes = [...foo]
/*推薦使用 `Array.from` 將 array-like[類數組] 轉換爲對象 */ const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);
/*推薦使用 `Array.from` 實現可迭代數組方法而不是經過 ... */ // bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, fn);
array-callback-return
/*推薦使用 `Array.from` 實現可迭代數組方法而不是經過 ... */ // good [1, 2, 3].map(x => x + 1); // 優化寫法、代碼簡潔易懂
/* 數組換行格式 優化 */ // bad const arr = [ [0, 1], [2, 3], [4, 5], ]; // good const arr = [[0, 1], [2, 3], [4, 5]];
prefer-destructuring
對象結構/* 對象結構 帶來的更加簡潔的代碼 */ // bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; }
prefer-destructuring
函數參數結構// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
prefer-destructuring
數組結構const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
...
...
這裏的核心就是減小構造函數的使用、多使用 經過 class 來進行 類的建立、constructor、extends 實現繼承、構造函數等 原始的方法。
// bad function Queue(contents = []) { this.queue = [...contents]; } Queue.prototype.pop = function () { const value = 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; } }
模塊化的 導入、導出。
// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;
...
因爲篇幅有限,這裏就不作過多的描述了,詳情能夠查看 Airbnb eslint 規則
我以爲任什麼時候候都須要這個規範!!!
不管是一我的,仍是 前端小組,甚至全公司的 大前端開發團隊 都是須要的!!!
如何定製這個規範
CODE
代碼層面實現藉助ESLint的autofix功能,在保存代碼的時候,自動將拋出error的地方進行fix。由於咱們項目是在webpack中引入eslint-loader來啓動eslint的,因此咱們只要稍微修改webpack的配置,就能在啓動webpack-dev-server的時候,每次保存代碼同時自動對代碼進行格式化。
// webpack.config.base.js or webpack.config.dev.js const path = require('path') module.exports = { module: { rules: [ { test: /\.(js|vue|jsx)$/, loader: 'eslint-loader', enforce: 'pre', include: [path.join(__dirname, 'src')], options: { fix: true } } ] }
lint
lint 規則層面:秉承着 一個原則, 漸進式 規則完善,從最基本的 規範到 逐步 健全的規範落實,結合 code review 逐漸完善。
對了,關鍵點就是 如何落實這個規範!!!
前端IDE開發的選擇,從大學階段的 DW
(Adobe Dreamweaver)、Notepad++
等等,再到後面的 Sublime
、Webstorm
再到後面的 Atom
、Visual Studio Code (VScode)
。
IDE 不斷的變化過程當中也給了咱們 更加高效編程的選擇
在 vscode 中的設置中配置(新舊不一樣版本的 vscode setting.json 的展示形式是不同的)
可是這個 格式化 每每只是最最進本的格式化,在前端如此多的 語言中很顯然是不夠用的,下面,咱們就主要介紹下 `Prettier`
在 vscode 的應用商店進行 搜索(Prettier - Code formatter )下載安裝 在項目的根目錄建立 Prettier 的配置文件 `.prettierrc` Prettier 格式化的配置文件文檔地址: https://prettier.io/docs/en/options.html 基本的配置文件格式以下:
{ "singleQuote": true, "trailingComma": "es5", "printWidth": 140, "semi": true, "bracketSpacing": true, "overrides": [ { "files": ".prettierrc", "options": { "parser": "json" } } ] }
那麼,咱們來看下 Prettier 作了哪些事情
能支持jsx
也能支持css
首先確定是須要安裝prettier,而且你的項目中已經使用了ESLint,有eslintrc.js配置文件。
eslint-plugin-prettier插件會調用prettier對你的代碼風格進行檢查,其原理是先使用prettier對你的代碼進行格式化,而後與格式化以前的代碼進行對比,若是過出現了不一致,這個地方就會被prettier進行標記。
//.eslintrc { "plugins": ["prettier"], "rules": { "prettier/prettier": "error" } }
這樣就 能夠經過 eslint 來 extend prettier 的規範,最後結合 webpack 的 module 中 對於 js、vue、jsx 文件的 loader 處理,來實現 實時的 lint 。
那麼 迴歸到最後,咱們去架構這個項目的時候,從 前端編碼規範層面去考慮的話,咱們的項目 最少須要的幾個 配置文件是這樣子的:
webpack
是 構建根本,結合各種插件使用
結合 vscode
終極格式化 咱們的代碼,一鍵化操做帶你飛~
eslint
結合 各種 eslint 的規則。 進行 強/弱 類型提示 (0、一、2)
{ "presets": ["es2015", "stage-1", "react"], "plugins": ["transform-runtime", "transform-decorators-legacy"], "env": {} }
結合 babel
的各種 loader 進行 ES 的語法預編譯處理,這裏因爲時間關係就不仔細去闡述了。
一套好的規範,能夠解決不想遇到的意外的bug、能夠規範本身的編碼習慣、可讓 code Review 更加簡單。 好處多多,有待不斷摸索,前期天然回遇到一些困難,但結果是值得期待的~
GitHub 地址:(歡迎 star 、歡迎推薦 : )