• 《前端之路》 之 前端开发规范 从制定到实施


    前端开发规范 从制定到实施

    在我们开始这个题目的时候,我们应该思考下面几个问题:

    1. 前端开发为什么需要 开发规范?
    2. 前端开发规范是什么?
    3. 什么时候需要这个规范?
    4. 如何制定这个规范?
    5. 如何落实这个规范?

    一、前端开发为什么需要 开发规范?

    why?

    前端还在 刀耕火种的时代的时候,前端是没有 工程 这个概念的。更多是切图仔这个概念,(将设计师设计出来的 web 、app、h5 的 UI 通过 PS 切图 然后再通过 HTML、CSS 实现出来)的这么一个工种。那么随着 互联网兴起到后来的移动互联网发展,To C 产品需求 精细化, 用户对于 C 端产品越来越挑剔也促使着 前端工程化越来越规范化了。 渐渐的前端工程形成,那么随之而来的就是 工程化 带来的 规范化

    回到 why 的问题上来,我们先举一个简单的例子来说,

    可能 工程化 这个名词在很多的后端语言中早早的就已经形成了,但前端 这么一门到现在大学课程都没开课的工种,全靠大学毕业后工作中自学积累而来,那么我们是否可以说,现阶段前端搞的好的人,Ta 的自学能力一定不会差。

    二、前端开发规范是什么?

    what?

    什么是前端开发规范?

    HTMLCSSJavascriptTypeScript 的代码编写规范,这里我们着重讲一下 JS 的 编码规范

    1、Types

    javascript 的数据类型

    1.1 基本数据类型

    • string
    • number
    • boolean
    • null
    • undefined
    • symbol
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    

    1.2 引用数据类型

    • object
    • array
    • function
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9
    

    以上则 是 基础数据 在 coding 的时候的基本规范。

    2、References

    变量、常量、定义规范

    • 2.1 eslint: prefer-const, no-const-assign
    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
    
    建议使用 const 定义常量,可以阻止一些 重复定义导致的 bug
    
    • 2.2 eslint: no-var
    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }
    
    推荐使用 let 来定义变量,形成块级作用域,减少因为变量提升导致的bug
    

    3、Objects

    对象 定义规范

    • 3.1 eslint: no-new-object
    // bad
    const item = new Object();
    
    // good
    const item = {};
    
    推荐使用 对象字面量来定义空对象,而不是通过 new 实例化进行操作
    
    • 3.2 动态属性名 使用 计算属性
    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };
    
    • 3.3 eslint: 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;
      },
    };
    
    推荐 在给对象添加方法的时候,使用 简化符号
    
    • 3.4 eslint: object-shorthand
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };
    
    方法名如果和对象的属性名称相同的时候,推荐使用简化符号编写
    
    • 3.5 在使用 object-shorthand 的时候,推荐先写出简化符号的属性或者方法
    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      episodeOne: 1,
      lukeSkywalker,
      anakinSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
    };
    
    • 3.6 eslint: 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带有 符号等
    
    • 3.7 eslint: 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));
    
    推荐理由是:这些方法可能被有关对象上的属性所遮蔽
    
    • 3.8 对象扩展符 比使用 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倍吧
    

    4、Arrays

    • 4.1 eslint: no-array-constructor
    /*推荐使用通过字面量创建对象、数组*/
    // bad
    const items = new Array();
    // good
    const items = [];
    
    • 4.2 Use Array#push
    /*推荐使用 push 来进行 stack add */
    // bad
    someArr[someArr.length] = 'xxxxsssswwww'
    // good
    someArr.push('xxxxsssswwww')
    
    • 4.3 Use array spreads ... to copy arrays
    /*推荐使用 `...` 进行数组 复制 */
    // bad
    for(i=0; i<arr.length; i++) { newArr[i] = arr[i] }
    // good
    let newArr = [...arr]
    
    • 4.4 use spreads ... instead of Array.from
    /*推荐使用 `...` 将可迭代对象转换为数组 */
    // bad
    const foo = document.querySelectorAll('.foo'); nodes = Array.from(foo)	// array[]
    // good
    let nodes = [...foo]
    
    • 4.5 Use Array.from for converting an array-like object to an array
    /*推荐使用 `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);
    
    • 4.6 Use Array.from instead of spread ... for mapping over iterables
    /*推荐使用 `Array.from` 实现可迭代数组方法而不是通过 ... */
    // bad
    const baz = [...foo].map(bar);
    // good
    const baz = Array.from(foo, fn);
    
    • 4.7 eslint: array-callback-return
    /*推荐使用 `Array.from` 实现可迭代数组方法而不是通过 ... */
    // good
    [1, 2, 3].map(x => x + 1);
    // 优化写法、代码简洁易懂
    
    • 4.8 Use line breaks after open and before close array brackets
    /* 数组换行格式 优化 */
    // bad
    const arr = [
      [0, 1], [2, 3], [4, 5],
    ];
    
    // good
    const arr = [[0, 1], [2, 3], [4, 5]];
    

    5、Destructuring - 解构

    • 5.1 eslint: 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}`;
    }
    
    • 5.2 eslint: 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}`;
    }
    
    • 5.3 eslint: prefer-destructuring 数组结构
    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
    

    6、 String

    ...

    7、 function

    ...

    8、Classes & Constructors

    这里的核心就是减少构造函数的使用、多使用 通过 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;
      }
    }
    

    9、Modules

    模块化的 导入、导出。
    
    // 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;
    

    10、space

    ...

    由于篇幅有限,这里就不做过多的描述了,详情可以查看 Airbnb eslint 规则

    三、什么时候需要这个规范?

    我觉得任何时候都需要这个规范!!!

    无论是一个人,还是 前端小组,甚至全公司的 大前端开发团队 都是需要的!!!

    四、如何制定这个规范?

    如何定制这个规范

    1、 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
            }
          }
        ]
    }
    

    2、lint lint 规则层面:

    秉承着 一个原则, 渐进式 规则完善,从最基本的 规范到 逐步 健全的规范落实,结合 code review 逐渐完善。

    五、如何落实这个规范?

    对了,关键点就是 如何落实这个规范!!!
    

    1、IDE 的选择

    前端IDE开发的选择,从大学阶段的 DW(Adobe Dreamweaver)、Notepad++ 等等,再到后面的 SublimeWebstorm 再到后面的 AtomVisual Studio Code (VScode)

    IDE 不断的变化过程中也给了我们 更加高效编程的选择

    2、IDE 的 本地设置文件 setting.json

    在 vscode 中的设置中配置(新旧不同版本的 vscode setting.json 的展现形式是不一样的)
    

    但是这个 格式化 往往只是最最进本的格式化,在前端如此多的 语言中很显然是不够用的,下面,我们就主要介绍下 `Prettier`
    

    3、Prettier - Code formatter 格式化插件的使用

    在 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

    4、ESLint 与 Prettier配合使用

    首先肯定是需要安装prettier,并且你的项目中已经使用了ESLint,有eslintrc.js配置文件。

    4.1 配合ESLint检测代码风格

    eslint-plugin-prettier插件会调用prettier对你的代码风格进行检查,其原理是先使用prettier对你的代码进行格式化,然后与格式化之前的代码进行对比,如果过出现了不一致,这个地方就会被prettier进行标记。

    //.eslintrc
    {
      "plugins": ["prettier"],
      "rules": {
        "prettier/prettier": "error"
      }
    }
    

    这样就 可以通过 eslint 来 extend prettier 的规范,最后结合 webpack 的 module 中 对于 js、vue、jsx 文件的 loader 处理,来实现 实时的 lint 。

    5、项目架构中 应该具备的 配置文件

    那么 回归到最后,我们去架构这个项目的时候,从 前端编码规范层面去考虑的话,我们的项目 最少需要的几个 配置文件是这样子的:
    
    5.1 、webpack.config.js

    webpack 是 构建根本,结合各类插件使用

    5.2 、prettierrc

    结合 vscode 终极格式化 我们的代码,一键化操作带你飞~

    5.3 、eslintrc

    eslint 结合 各类 eslint 的规则。 进行 强/弱 类型提示 (0、1、2)

    5.4 、babelrc
    {
      "presets": ["es2015", "stage-1", "react"],
      "plugins": ["transform-runtime", "transform-decorators-legacy"],
      "env": {}
    }
    

    结合 babel 的各类 loader 进行 ES 的语法预编译处理,这里由于时间关系就不仔细去阐述了。

    六 、总结

    一套好的规范,可以解决不想遇到的意外的bug、可以规范自己的编码习惯、可以让 code Review 更加简单。
    好处多多,有待不断摸索,前期自然回遇到一些困难,但结果是值得期待的~
    

    GitHub 地址:(欢迎 star 、欢迎推荐 : )

    前端开发规范 从制定到实施

  • 相关阅读:
    DOCTYPE和namespace
    由浅入深漫谈margin属性
    checkbox的完美用户体验
    XSL 属性模板的运用
    各浏览器里默认的表单控件(form controls)
    简单form标准化实例(二):语义结构
    zindex在IE中的迷惑(二)
    最简单的清除浮动的方法
    Default style sheet for HTML 4
    PNG透明背景图片的无界应用
  • 原文地址:https://www.cnblogs.com/erbingbing/p/10783641.html
Copyright © 2020-2023  润新知