美文网首页
前端开发代码规范(三)

前端开发代码规范(三)

作者: Yinzhishan | 来源:发表于2022-07-31 11:38 被阅读0次

    JavaScript编码规范

    1.类型

    1.1基本类型: 直接存取基本类型。

    • string
    • number
    • boolean
    • null
    • undefined
    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
    

    2.引用

    2.1 [强制] 对所有的引用使用 const ;不要使用 var

    为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
    

    2.2 [强制] 需要可变动的引用,使用 let 代替 var

    为什么?因为 letconst是块级作用域,而 var 是函数作用域。
    constlet 只存在于它们被定义的区块内。

    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    
    // bad
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }
    

    3.对象

    3.1 [强制] 禁止使用[保留字]作为属性名

    因为在IE8及以下版本存在问题,使用同义词替换它

    // bad
    const item = {
      class: 'dark'
    };
    
    // good
    const item = {
      type: 'dark'
    };
    

    3.2 [强制] 禁止在对象的最后一个属性值后添加,

    IE6和IE7下会存在js报错(同上)

    // bad
    const item = {
      type: 'dark',
      element: 'flame',
    };
    
    // good
    const item = {
      type: 'dark',
      element: 'flame'
    };
    

    3.3 [强制] 使用字面值创建对象

    // bad
    const item = new Object();
    
    // good
    const item = {};
    

    3.4 [强制] 使用对象方法的简写

    // bad
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // good
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };
    

    3.5 [强制] 使用对象属性值的简写

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };
    

    3.6 [推荐] 在对象属性声明前把简写的属性分组

    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      episodeOne: 1,
      twoJedisWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJedisWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4,
    };
    

    4.数组

    4.1 [强制] 使用字面量创建数组

    // bad
    const item = new Array();
    
    // good
    const item = [];
    

    4.2 [强制] 向数组末尾增加元素时,使用 Array.push() 代替直接赋值

    let magicBook = [];
    
    // bad
    magicBook[magicBook.length] = 'Expelliarmus';
    
    // good
    magicBook.push('Expelliarmus');
    

    4.3 [强制] 浅拷贝(shallow copy)数组时,使用 Array.slice() 或拓展运算符 ... 复制数组

    浅拷贝:由于对象和数组在赋值的时候都是引用传递,赋值的时候只是传递一个指针(见1.类型),浅拷贝的数组中的对象依旧是引用。

    深拷贝(deep copy): 可以使用jqueryjQuery.extend 或者 npm的 deep*copy 方法等。

    let items = [{ id: 1 },{ id: 2}];
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    // bad
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    itemsCopy = items.slice();
    
    // good
    const itemsCopy = [...items];
    
    //is shallow copy?
    items[0] == itemsCopy[0]; // => true 为浅拷贝
    

    4.4 [推荐] 使用 Array.from() 把一个类数组对象转换成数组。

    const foo = document.querySelectorAll('.foo');
    const nodes = Array.from(foo);
    

    5.字符串

    5.1 [建议] 使用单引号包裹字符串

    // bad
    const name = "Harry Potter";
    
    // good
    const name = 'Harry Potter';
    

    5.2[强制] 程序化生成字符串时,使用模板字符串代替字符串连接

    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }
    

    6.函数

    6.1 [强制] 禁止在非函数代码块中(如 if while)声明函数

    // bad
    if (flag) {
      function castSpell(){
        // do something...
      }
    }
    
    // good
    function castAvada() {
      return 'Avada Kedavra';
    }
    
    let castSpell;
    
    if (flag) {
      castSpell = castAvada;
    }
    

    6.2 [强制] 禁止把参数名命名为arguments,会取代函数中的arguments

    // bad
    function nope(name, options, arguments) {
      // ...stuff...
    }
    
    // good
    function yup(name, options, args) {
      // ...stuff...
    }
    

    6.3 [推荐] 不要使用 arguments。可以选择 rest 语法 ... 替代

    为什么?使用 ... 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    

    6.4 [强制] 禁止使用全局严格模式

    // yes
    function handel() {
      "use strict";
    }
    
    // no
    "use strict";
    function handel() {
    
    }
    

    6.5 [推荐] 使用函数声明代替函数表达式。

    为什么?因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得箭头函数可以取代函数表达式。

    // bad
    const foo = function () {
    };
    
    // good
    function foo() {
    }
    

    6.6 [推荐] 直接给函数的参数指定默认值,不要使用一个变化的函数参数。

    // really bad
    function handleThings(opts) {
      // 不!我们不应该改变函数参数。
      // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
      // 但这样的写法会造成一些 Bugs。
      //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

    6.7 [推荐] 箭头函数代替function

    // bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });
    
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    

    如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 return 都省略掉。如果不是,那就不要省略。

    // good
    [1, 2, 3].map(x => x * x);
    
    // good
    [1, 2, 3].reduce((total, n) => {
      return total + n;
    }, 0);
    

    7.属性

    7.1 [强制] 使用 . 来访问对象的属性

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;
    

    7.2 [强制] 当通过变量访问属性时使用中括号 []

    const luke = {
      jedi: true,
      age: 28,
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    const isJedi = getProp('jedi');
    

    8.变量

    8.1 [强制] 使用 let const 替换代码中的var,代码中不要出现魔幻数字,用const提前声明这些常量

    // bad
    var a = 10;
    var arr = [1,2,3];
    superPower = new SuperPower();
    
    // good
    const a = 10;
    let arr = [1,2,3];
    const superPower = new SuperPower();
    

    8.2 [强制] 如果需要要声明一个全局变量,必须使用window.

    // bad
    spell = 'Expelliarmus';
    
    // good
    window.spell = 'Expelliarmus';
    

    9.解构

    9.1 [推荐] 使用解构存取和使用多属性对象。

    为什么?因为解构能减少临时引用属性。

    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(obj) {
      const { firstName, lastName } = obj;
      return `${firstName} ${lastName}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }
    

    9.2 [推荐] 对数组使用解构赋值。

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
    

    9.3 [推荐] 需要回传多个值时,使用对象解构,而不是数组解构。

    为什么?增加属性或者改变排序不会改变调用时的位置。

    // bad
    function processInput(input) {
      // then a miracle occurs
      return [left, right, top, bottom];
    }
    
    // 调用时需要考虑回调数据的顺序。
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // then a miracle occurs
      return { left, right, top, bottom };
    }
    
    // 调用时只选择需要的数据
    const { left, right } = processInput(input);
    

    10.构造器

    10.1 [推荐] 总是使用 class。避免直接操作 prototype

    为什么? 因为 class 语法更为简洁更易读。

    // 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;
      }
    }
    

    10.2 [推荐] 使用 extends 继承。

    为什么?因为 extends 是一个内建的原型继承方法并且不会破坏 instanceof

    // bad
    const inherits = require('inherits');
    function PeekableQueue(contents) {
      Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function() {
      return this._queue[0];
    }
    
    // good
    class PeekableQueue extends Queue {
      peek() {
        return this._queue[0];
      }
    }
    

    10.3 [推荐] 方法可以返回 this 来帮助链式调用。

    // bad
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
    };
    
    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined
    
    // good
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }
    
      setHeight(height) {
        this.height = height;
        return this;
      }
    }
    
    const luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
    

    11.模块

    11.1 [推荐] 总是使用模组 (import/export) 而不是其他非标准模块系统。

    为什么?模块就是未来,让我们开始迈向未来吧。

    // 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;
    

    11.2 [强制] 不要使用通配符*

    为什么?这样能确保你只有一个默认 export

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    

    11.3 [推荐] 不要从 import 中直接 export

    为什么?虽然一行代码简洁明了,但让 importexport 各司其职让事情能保持一致。

    // bad
    // filename es6.js
    export { es6 as default } from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    

    12.Iterators and Generators

    12.1 [推荐] 不要使用 iterators。使用高阶函数例如 map()reduce() 替代 for*of

    为什么?这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach((num) => sum += num);
    sum === 15;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;
    

    12.2 现在还不要使用generators

    为什么?因为它们现在还没法很好地编译到 ES5。

    13比较运算符和等号

    13.1 [强制] 优先使用 ===!== 而不是 ==!=.

    13.2 [推荐] 使用简写。

    // bad
    if (name !== '') {
      // ...stuff...
    }
    
    // good
    if (name) {
      // ...stuff...
    }
    
    // bad
    if (collection.length > 0) {
      // ...stuff...
    }
    
    // good
    if (collection.length) {
      // ...stuff...
    }
    

    13.3条件表达式的强制类型转换遵循以下规则:

    • 对象 被计算为 true
    • undefined 被计算为 false
    • null 被计算为 false
    • 布尔值 被计算为 布尔的值
    • 数字 如果是 +0, *0, 或是 NaN 被计算为 false , 否则为 true
    • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    if([0]) {
      // true 因为数组是对象,对象被计算为true
    }
    
    if([]){
     // true 因为数组是对象,对象被计算为true
    }
    

    14.代码块

    14.1 [强制] 使用大括号包裹所有的多行代码块。

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function() { return false; }
    
    // good
    function() {
      return false;
    }
    

    14.2 [强制] 如果通过 ifelse 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。

    // bad
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }
    
    // good
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }
    

    15.注释

    15.1 [强制] 使用/** ... */ 作为多行注释。包含描述、指定所有参数和返回值的类型和值。

    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed in tag name
     *
     * @param {String} tag
     * @return {Element} element
     */
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    

    15.2 [强制] 使用 // 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。

    // bad
    const active = true;  // is current tab
    
    // good
    // is current tab
    const active = true;
    
    // bad
    function getType() {
      console.log('fetching type...');
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // good
    function getType() {
      console.log('fetching type...');
    
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    

    15.3 [推荐] 给注释增加 FIXMETODO 的前缀。

    这可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME ** need to figure this out 或者 TODO ** need to implement

    使用 // FIXME: 标注问题。

    class Calculator {
      constructor() {
        // FIXME: shouldn't use a global here
        total = 0;
      }
    }
    

    使用 // TODO: 标注问题的解决方式。

    class Calculator {
      constructor() {
        // TODO: total should be configurable by an options param
        this.total = 0;
      }
    }
    

    16.空白

    16.1 [强制] 使用 2 个空格作为缩进。

    // bad
    function() {
    ∙∙∙∙const name;
    }
    
    // bad
    function() {
    ∙const name;
    }
    
    // good
    function() {
    ∙∙const name;
    }
    

    16.2 [强制] 在花括号前放一个空格。

    // bad
    function test(){
      console.log('test');
    }
    
    // good
    function test() {
      console.log('test');
    }
    
    // bad
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
    // good
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    

    16.3 [强制] 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。

    // bad
    if(isJedi) {
      fight ();
    }
    
    // good
    if (isJedi) {
      fight();
    }
    
    // bad
    function fight () {
      console.log ('Swooosh!');
    }
    
    // good
    function fight() {
      console.log('Swooosh!');
    }
    

    16.4 [强制] 使用空格把运算符隔开。

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
    

    16.5 [强制] 在文件末尾插入一个空行。

    // bad
    (function(global) {
      // ...stuff...
    })(this);
    
    // bad
    (function(global) {
      // ...stuff...
    })(this);↵
    ↵
    
    // good
    (function(global) {
      // ...stuff...
    })(this);↵
    

    16.6 [推荐] 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。

    // bad
    $('##items').find('.selected').highlight().end().find('.open').updateCount();
    
    // bad
    $('##items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();
    
    // good
    $('##items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();
    
    // bad
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    

    16.7 [推荐] 在块末和新语句前插入空行。

    // bad
    if (foo) {
      return bar;
    }
    return baz;
    
    // good
    if (foo) {
      return bar;
    }
    
    return baz;
    
    // bad
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;
    
    // good
    const obj = {
      foo() {
      },
    
      bar() {
      },
    };
    
    return obj;
    

    17.逗号

    17.1 [强制] 在变量或表达式后面添加逗号,不要出现逗号,在前

    // bad
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };
    
    // good
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };
    

    17.2 [强制] 去掉不必要的逗号,这在IE67下会出现怪异行为。

    const hero = {
      name:'hongxin',
      age:18,
    }
    
    const heros = [
      'Batman',
      'Superman',
    ]
    

    18.分号

    18.1 [推荐] 每条语句必须加分号。

    // bad
    (function() {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (() => {
      const name = 'Skywalker';
      return name;
    })();
    
    // good (防止函数在两个 IIFE 合并时被当成一个参数)
    ;(() => {
      const name = 'Skywalker';
      return name;
    })();
    

    19.类型转换

    19.1 [推荐] 字符串转换

    //  => this.reviewScore = 9;
    
    // bad
    const totalScore = this.reviewScore + '';
    
    // good
    const totalScore = String(this.reviewScore);
    

    19.2 [推荐] 布尔转换

    const age = 0;
    
    // bad
    const hasAge = new Boolean(age);
    
    // good
    const hasAge = Boolean(age);
    
    // good
    const hasAge = !!age;
    

    19.3 [强制] 使用parseInt转换数字时总是带上转换基数

    // bad
    parseInt('0x10'); // => 16
    
    parseInt('09'); // => 0 (ie8下, ie9+及chrome为9)
    
    // good
    parseInt('09',10); // => 9
    

    19.4 [谨慎] 小心使用位操作运算符。

    数字会被当成 64 位值,但是位操作运算符总是返回 32 位的整数。位操作处理大于 32 位的整数值时还会导致意料之外的行为。最大的 32 位整数是 2,147,483,647

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> *2147483648
    2147483649 >> 0 //=> *2147483647
    

    20.命名规则

    20.1 [强制] 避免单字母命名。命名应具备描述性。

    // bad
    function q() {
      // ...stuff...
    }
    
    // good
    function query() {
      // ..stuff..
    }
    

    20.2 [强制] 以驼峰形式命名变量、函数和实例

    变量和实例应尽量以名词为主,函数名尽量以动词+名词组合,返回布尔值的函数尽量以is、has打头

    // good
    const communityList = [];
    
    function collectShells(){
      return shells;
    }
    
    function isAnimal(){
      return bool;
    }
    

    20.3 [强制] 常量必须全部大写,多个单词以下划线分隔

    const LANEHUB = 10;
    const LANEHUB_JAVASCRIPT = 100;
    

    20.4 [强制] 使用帕斯卡式命名(大驼峰)构造函数或类。

    当你导出单例、函数库、空对象时使用帕斯卡式命名

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
    

    20.5 [强制] 不要使用下划线 _ 结尾或开头来命名属性和方法。

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';
    

    20.6 [强制] 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。

    // file contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // in some other file
    // bad
    import CheckBox from './checkBox';
    
    // bad
    import CheckBox from './check_box';
    
    // good
    import CheckBox from './CheckBox';
    

    21.ECMAScript 规范 [学习]

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,于2015年6月批准通过。ECMAScript6的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。让代码更加准确,更易于阅读。
    —— 推荐地址

    JavaScript最强势的监工-正在迈向ES8,所以让我们来了解下ES7 and ES8(官方称ES2016 and ES2017),幸运的是,他们比ES6标准功能少好多好多
    —— 推荐地址

    相关文章

      网友评论

          本文标题:前端开发代码规范(三)

          本文链接:https://www.haomeiwen.com/subject/wontwrtx.html