代碼規範(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();
相關文章
相關標籤/搜索