代码规范(1)之 vue-cli的eslint 和 Airbnb JavaScript Style

 摆脱使人抓狂的ESlint 语法检测配置说明javascript

Airbnb JavaScript 编码风格指南(2018年最新版)css

 vue-cli脚手架build目录中的webpack.base.conf.js配置文件html

注释

前端开发规范:命名规范、HTML 规范、CSS 规范、JavaScript 规范前端

/** 方法说明
  * @method 方法名
  * @for 所属类名
  * @param {参数类型}参数名 参数说明
  * @return {返回值类型} 返回值说明
  */
  function num(a) {
    return a;
  }
  1. 使用空格,而不是制表符
  2. 使用两个空格(而不是四个)进行缩进
  3. 不要再使用var
  4. 箭头函数是首选;箭头函数提供了简洁的语法,并解决了this 在函数中不肯定性的一些问题
  5. 使用模板字符串而不是拼接字符串
  6. for…of是for循环的首选类型
  7. 常量应该用全大写字母命名,用下划线分隔
  8. 使用单引号,而不是双引号

eslint

ESlint是一个语法规则和代码风格检查工具,能够用来保证代码风格统一,方便之后维护。 vue

使用vue-cli建立基本项目,默认安装ESlint。java

build/webpack.base.conf.js下:webpack

// 引入config目录下的index.js配置文件,主要用来定义一些开发和生产环境的属性,其中包含是否使用 eslint 的判断语句
const config = require('../config')

// ...

// 建立 eslint 规则
const createLintingRule = () => ({
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})

  // module用来解析不一样的模块
  module: {
    rules: [
        // 使用 eslint 判断
      ...(config.dev.useEslint ? [createLintingRule()] : []),
     ]   
  }

 

config/index.jsgit

module.exports = {
  dev: {
    // ...

    // Use Eslint Loader 是否使用ESlint?
    // If true, your code will be linted during bundling and
    // linting errors and warnings will be shown in the console.
      // 代码在执行过程当中,将会在console中显示错误 和 警告
    useEslint: true,
    // If true, eslint errors and warnings will also be shown in the error overlay。 eslint显示错误和警告的错误也将被覆盖
    // in the browser.
    showEslintErrorsInOverlay: false,
  }
   // ....
}

.eslintrc.js文件自定义规则:github

vue-cli中的ESlint配置文件eslintrc.js详解web

vue-cli下ESlint 配置说明

Airbnb JavaScript Style

参考文章:Airbnb的JavaScript风格指南(ES5)

类型

  • 基本类型

    • 对于基本类型的操做时对值的操做

  • 复杂类型

    • 对于复杂类型的操做是对引用的操做

对象

  • 尽可能使用字面量建立对象

  • 不要使用保留字做为属性键值

  • 使用可读性强的同义词来代替保留字

数组

  • 尽可能使用字面量建立数组

  • 使用arr.push()方法来添加元素

  • 复制数组使用arr.slice

字符串

  • 使用单引号''定义字符串

  • 超过100个字符串应该写成多行形式并使用字符串链接符+链接(过分使用字符串链接符可能会影响性能 )

  • 在代码中构建字符串时,使用arr.join()方法,而不是使用字符串链接符+

函数

  • 永远不要再非函数代码块(if,while)中声明函数,可是能够将函数复制给一个变量

  • 永远不要将一个参数命名为arguments,这么作会覆盖每一个函数默认的arguments对象

属性

  • 使用点号.来获取对象的属性

  • 当须要获取的属性键值是一个变量来给出,可使用[]来获取

变量

  • 声明变量的使用永远要写上var,不这么作的话将会获得一个全局变量,并所以污染全局变量的命名空间。(如今通常用constlet

  • 每个变量声明使用一个单独的var

  • 将未赋值变量的声明放在最后,这有利于后面再给变量赋值的使用须要依赖另外一个已赋值变量的状况

  • 将变量声明放在其做用域的最顶端,这样能够避免变量提高所带来的问题

变量提高

  • 变量的声明语句会被解释器自动提高到其做用域的最顶部,但其赋值的语句不会被提高。

  • 匿名函数表达式的变量声明会被提高,但函数体不会被提高。

  • 有命名的函数表达式的变量声明会被提高,但函数名和函数体都不会被提高。

  • 函数声明时解释器会将函数名和函数体都提高到做用域顶部。

比较运算符

  • 使用===!==比使用==!=更理想

  • 条件语句在判断表达式值的使用,会使用ToBoolean抽象方法将结果强制转化为布尔值

    • Objects转化为true

    • Undefined转化为false

    • Null转化为false

    • Booleans不变

    • Numbers若是是+0, -0或NaN转化为false, 不然转化为true

    • Strings若是是空字符串''转化为false, 不然转化为true

  • 使用简短形式

空白符

  • 缩进2个空格

  • 左大括号以前留一个空格

  • 控制语句if,while的作小括号留一个空格,函数的阐述列表前不要留空格

  • 将运算符用空格隔开

  • 文件最后以一个单独的换行符结尾。

  • 遇到很长的方法调用链,使用换行缩进的方式(参照下面的代码),并以点号.开头,强调此行是一个方法而非一个新的语句。

// 不推荐
$('#items').find('.selected').highlight().end().find('.open').updateCount();
  • 在代码块结束和新语句之间留一个空行。

逗号

  • 放在行首的逗号: 不要使用

  • 对象或数组末尾额外的逗号: 不要使用

分号

  • 请使用

类型转化和强制转化

  • 在语句开始的时候执行类型的强制转化

  • 字符串

// 推荐
var totalScore = '' + this.reviewScore;

// 推荐
var totalScore = this.reviewScore + ' total score';
  • 数字类型转化时使用parseInt,而且老是带上基数
// 推荐
var val = Number(inputValue);

// 推荐
var val = parseInt(inputValue, 10);
  • 若是你遇到一些极端状况,parseInt成为了瓶颈,而且由于性能因素须要使用移位操做,留下注释来解释你这么作的缘由。
// 推荐
/**
 * parseInt是我代码缓慢的元凶,
 * 使用移位操做来将字符串转换成数字可解此忧
 */
var val = inputValue >> 0;
  • 布尔值
var age = 0;

// 不推荐
var hasAge = new Boolean(age);

// 推荐
var hasAge = Boolean(age);

// 推荐
var hasAge = !!age;

命名规范

  • 避免单字母的命名,尽可能使用有意义的命名方式。

  • 对象、函数、实例命名时,使用骆驼命名(小驼峰命名,例如:thisIsMyObject)

  • 构造方法或类的命名使用帕斯卡命名(大驼峰命名)。

  • 命名私有属性的时候,如下划线_开头

  • 要保存一个到this的引用,请使用_this来命名变量。

  • 给你的函数命名,这将有利于调试时代码栈的追踪。

// 不推荐
var log = function (msg) {
  console.log(msg);
};

// 推荐
var log = function log(msg) {
  console.log(msg);
};
  • 若是你的源码文件中只导出(exports)了一个类,请保持你的文件名与类名一致
// 文件内容
class CheckBox {
  // ...
}
module.exports = CheckBox;

// 在其余文件中
// 不推荐
var CheckBox = require('./checkBox');

// 不推荐
var CheckBox = require('./check_box');

// 推荐
var CheckBox = require('./CheckBox');

属性存取器

  • 属性存取器方法不是必需的。

  • 若是你要定义属性存取器,按照getVal()和setVal('hello')的模式来命名。

// 不推荐
dragon.age();

// 推荐
dragon.getAge();

// 不推荐
dragon.age(25);

// 推荐
dragon.setAge(25);
  • 若是属性是布尔型,使用isVal()或hasVal()的形式
// 不推荐
if (!dragon.age()) {
  return false;
}

// 推荐
if (!dragon.hasAge()) {
  return false;
}
  • 建立get()和set()函数也是能够的,但要保持其行为的一致性。
function Jedi(options) {
  options || (options = {});
  var lightsaber = options.lightsaber || 'blue';
  this.set('lightsaber', lightsaber);
}

Jedi.prototype.set = function set(key, val) {
  this[key] = val;
};

Jedi.prototype.get = function get(key) {
  return this[key];
};

构造器

  • 将新增方法赋值给对象的原型(prototype),而不要直接用新的对象覆盖对象的原型。 若是每次都覆盖对象的原型,就不能实现继承了,由于每次你都会直接覆盖掉基类的全部方法。

// 不推荐
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

// 推荐
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};
  • 方法能够返回this来帮助构建方法链式调用。
// 不推荐
Jedi.prototype.jump = function jump() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function setHeight(height) {
  this.height = height;
};

var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// 推荐
Jedi.prototype.jump = function jump() {
  this.jumping = true;
  return this;
};

Jedi.prototype.setHeight = function setHeight(height) {
  this.height = height;
  return this;
};

var luke = new Jedi();

luke.jump()
  .setHeight(20);
  • 建立一个自定义的toString()也是能够的,但要确保其正确性,并注意它对代码的其余地方会不会产生影响。
function Jedi(options) {
  options || (options = {});
  this.name = options.name || 'no name';
}

Jedi.prototype.getName = function getName() {
  return this.name;
};

Jedi.prototype.toString = function toString() {
  return 'Jedi - ' + this.getName();
};

事件

  • 当你须要将数据绑定到一个事件(不管是DOM事件仍是其余的事件)的时候,不要直接传入数据对象自己,将其包装到一个键值对象中再传入,由于你不能确保后续操做中不须要传入其余更多的数据到本事件中。例如, 下面这样就是很差的:

// 不推荐
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function (e, listingId) {
  // do something with listingId
});

更好的作法是:

// 推荐
$(this).trigger('listingUpdated', { listingId : listing.id });

...

$(this).on('listingUpdated', function (e, data) {
  // do something with data.listingId
});

模块

  • 模块应该以一个!开头,确保若是本模块被合并到另外一个第三方模块的末尾,而这个第三方模块忘记告终尾的分号的时候,不会报错。更多解释

  • 文件应该按骆驼命名(小驼峰命名)规则命名。若是文件夹中只有一个文件,文件夹名和文件名保持一致。

  • 添加一个名叫noConflict()的方法将处处模块设置为前一个版本并返回这个模块。

  • 在模块顶部老是要声明'use strict';

// fancyInput/fancyInput.js

!function (global) {
  'use strict';

  var previousFancyInput = global.FancyInput;

  function FancyInput(options) {
    this.options = options || {};
  }

  FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
  };

  global.FancyInput = FancyInput;
}(this);

jQuery

  • jQuery对象的变量命名以$开头。

// 不推荐
var sidebar = $('.sidebar');

// 推荐
var $sidebar = $('.sidebar');
  • 缓存jQuery选择器结果。
// 不推荐
function setSidebar() {
  $('.sidebar').hide();

  // ...stuff...

  $('.sidebar').css({
    'background-color': 'pink'
  });
}

// 推荐
function setSidebar() {
  var $sidebar = $('.sidebar');
  $sidebar.hide();

  // ...stuff...

  $sidebar.css({
    'background-color': 'pink'
  });
}
  • 使用级联形式$('.sidebar ul')$('.sidebar > ul')来查找DOM元素。

  • 使用find来查找某个范围内的jQuery对象。

// 不推荐
$('ul', '.sidebar').hide();

// 不推荐
$('.sidebar').find('ul').hide();

// 推荐
$('.sidebar ul').hide();

// 推荐
$('.sidebar > ul').hide();

// 推荐
$sidebar.find('ul').hide();
相关文章
相关标签/搜索