在咱们开始这个题目的时候,咱们应该思考下面几个问题: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 、欢迎推荐 : )