學習筆記——JavaScript 編碼規範

類型

基本類型

- string
 - number
 - boolean
 - null
 - undefined
 - symbol(表示獨一無二的值,使用時須要注意瀏覽器是否支持)
     //example
    const symbol1 = Symbol();
    const symbol2 = Symbol(42);
    const symbol3 = Symbol('foo');
    
    console.log(typeof symbol1);
    // expected output: "symbol"
    
    console.log(symbol3.toString());
    // expected output: "Symbol(foo)"
    
    console.log(Symbol('foo') === Symbol('foo'));
    // expected output: false

複雜類型

- array
- object
- function

聲明變量

//塊級做用域內有效
- let
//塊級做用域內有效 不可重複賦值
- const

對象

直接聲明

//bad
let obj = new Object();
//good
let obj = {};

動態屬性名

//bad
function getKey(key){
    return `${key}`
}
let obj = {
    id:1
    name:"jack"
}  
obj[getKey("age")] = 18;
console.log(obj.age) //18

//good
let obj = {
    name:"jack",
    age:18,
    [getKey("age")]:18
}

對象方法簡寫

//bad
let obj = {
    name:"jack",
    age:18,
    show:function(arg){
        console.log(arg)
    }
}  
//good
let obj = {
    name:"jack",
    age:18,
    show(arg){
        console.log(arg)
    }
}

屬性值簡寫

//bad
let age = 18;
let obj = {
    name:"jack",
    age:age
}
//good
let obj = {   
    age,//簡寫最好放前面
    name:"jack",
    "data-id":5//鍵名儘可能不加引號,除非沒有引號不合法
}

不要直接使用Object.prototype的方法

//不要直接使用Object.prototype的方法,如hasOwnProperty, propertyIsEnumerable和isPrototypeOf
//bad
let obj = {
    id:1,
    name:"jack"
}
obj.hasOwnProperty("name");
//good
Object.prototype.hasOwnProperty.call(obj,"name");
//best
var has = Object.prototype.hasOwnProperty;
has.call(obj,"name")

用變量的解構賦值代替Object.assign()作淺拷貝

//用變量的解構賦值代替Object.assign()作淺拷貝
//bad
let ori = {a:1,b:2};
let copy = Object.assign({},ori,{c:3});
//good
let ori = {a:1,b:2};
let copy = {...ori,c:3};//{a:1,b:2,c:3}
let {a,...notA} = copy; // notA={b:2,c:3}

數組

簡潔聲明

//bad
let arr = new Array();
//good
let arr = [];

使用push代替直接分配元素給數組

//bad
let arr = [];
arr[arr.length] = "abc";
//good
arr.push("abc");

擴展運算符...代替數組拷貝

//bad
let arr = [1,2,3];
let copy = [];
for(let i=0;i<len=arr.length,i++){
    copy[i] = arr[i]
}
//good
copy = [...arr]

轉換類數組的對象爲數組

let div = document.querySelectAll("div");
//good
let arr = Array.from(div);
//best
let arr = [...div]

數組方法中的return

//當function大括號只有一個表達式時,{}和rerun均可以省
//bad
[1,2,3].map(x=>{
    let y = x+1;
    return x*y
}) 
//good
[1,2,3].map(x=>x+1)

解構賦值

//object
//good
function getFullName(user){
    let {firstName,lastName} = user;
    return `${firstName}${lastName}`
}
//best
function getFullName({firstName,lastName}){
    return `${firstName}${lastName}`
}

//array
let arr = [1,2,3,4];
//bad
let first = arr[0];
let sec = arr[1];
//good
[first,sec] = arr

函數的多個返回值用對象解構賦值

//bad
function processInput(input){
    return [let,top,right,bottom]
}
//good
function processInput(input){
    return {let,top,right,bottom}
}
//use
let {left,bottom} = processInput(input);

字符串

使用單引號

//bad
let str = "hello world";
//good
let str = 'hello world'

儘可能別轉行

//有轉行時,固然字符數不超過100的狀況儘可能別轉行
//bad
let str = 'hello world,'+
          'balabalabala';
//good

let str = 'hello world,balabalabala'javascript

字符串變量拼接

//bad
let str = 'hello '+name+' !';
//good
let str =`hello ${name} !`;

函數

複雜名稱的函數賦值給一個簡潔變量名

//bad
  let foo= function(){}
  function foo(){}
  //good
  let foo = function getPageFooComponent(){}
  //use
  foo();

別在if while等語句中聲明函數

//bad
if(){
    function test(){}
}
//good
let test;
if(){
    test = ()=>{console.log("hello")}
}

別用arguments做爲參數名

//bad
function foo(name,arguments){}
//good
function foo(name,arg){}

擴展運算符...代替arguments

//bad
function test(){
    let args = Array.portotype.slice.call(arguments);
    return args.join('');
}
//good
function test(...args){
    return args.join('');
}

默認參數

//bad
funtion test(opt){
    let opt = opt || {}
}
//good
function test(opt={}){

}

別在參數體裏面計算

//bad
let a=1;
function test(b = a++){
    
}

將賦值的參數放在最後

//bad
function test(opt = {},name){
}
//good
function test(name,opt = {}){
}

別對參數從新賦值

//bad
function test(a){
    let a=1;
}
function test(a){
   if(!a){
    let a=1;
   }
}
//good
function test(a){
    let b = a || 1;
}
function test(a = 1){
  
}

類&構造方法

用class代替傳統的prototype手動方法

//bad
function Queue(contents = []){
    this.queue = [contents];
}
Queue.prototype.pop = function(){
    let value = this.queue[0];
    this.queue.spice(0,1);
    return value;
}
//good
class Queue {
    constructor(contents = []){
        this.queue = [contents]
    }
    pop(){
        let value = this.queue[0];
        this.queue.spice(0,1);
        return value;
    }
}

用extend作繼承

//good
class Dog extends Animal{
    yell(){
        return 'wangwang'
    }
}

this的指向

//bad
 Jedi.prototype.jump = function(){
     this.jumping = true;
     return true;
 }
 Jedi.prototype.setHeight= function(height){
     this.height = height;
 }
 let luck = new Jedi();
 luck.jump();
 luck.setHeight(20);
//good
class Jedi{
    jump(){
        this.jumping = true;
         return true;
    }
    setHeight(height){
        this.height = height;
    }
}
let luck = new Jedi();
luck.jump();
luck.setHeight(20);

子類的構造函數必須執行一次super函數

//bad
class test {
    constructor() {}//空constructor不須要
    
    getName() {
        return this.name;
    }
}
//bad
class test {
    constructor(...args) {
        super(...args)//只是爲了繼承constructor不須要
    }
}
//good
class test {
    constructor(...args) {
        super(...args)
        this.name = 'key'
    }
}

模塊

import/export

//bad
let AirbnbJavascriptGuide = require('./AirbnbJavascriptGuide ');
module.exports = AirbnbJavascriptGuide.es6;
//ok
import AirbnbJavascriptGuide  from './AirbnbJavascriptGuide ';
export default AirbnbJavascriptGuide.es6;
//best
import {es6} from './AirbnbJavascriptGuide ';
export default es6;

忌用通配符import

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

別在import時同時export

//bad
export { es6 as default } from './AirbnbJavascriptGuide ';
//good
import { es6 } from './AirbnbJavascriptGuide ';
export default es6;

同一個地址放在一個import

//bad 
import foo form 'foo';
...
import { name,age } from 'foo';
//good
import foo,{ name,age } form 'foo';
//best
import foo,{ 
            name,
            age 
            } form 'foo';

只有一個export時 用export default

//bad
export function foo() {}
//good
export default foo() {}

不要在import時用Webpack loader

//bad
import foo from  'css!sass!foo.scss';
//good
import foo from 'foo.css';

迭代遍歷

用map、every、filter,find,findIndex,some,reduce等代替for-in,for-of

let numbers = [1,2,3,4]
//bad
let sum = 0;
for(let num of numbers){
    sum += num;
}    
//good
let sum = 0;
numbers.forEach(num => sum += num);

//bad
let increaseByOne = [];
for(let i = 0;i< numbers.length;i++){
    increaseByOne .push(numbers[i]+1);
}
//good
let increaseByOne = numbers.map(num => num + 1);

正確的constructor的書寫

//good
let  test = function* (){
    //...
}

屬性

經過.訪問屬性

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

經過變量訪問屬性時使用中括號 []

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

##變量##css

用let和const聲明變量

//good
let superPower = new SuperPower();

提高

var 聲明會被提高至該做用域的頂部,但它們賦值不會提高

//bad
// 因爲變量提高的緣由,
// 在引用變量後再聲明變量是能夠運行的。
// 注:變量的賦值 `true` 不會被提高。
function example() {
  console.log(declaredButNotAssigned); // => undefined
  var declaredButNotAssigned = true;
}

匿名函數表達式的變量名會被提高,但函數內容並不會

function example() {
  console.log(anonymous); // => undefined

  anonymous(); // => TypeError anonymous is not a function

  var anonymous = function() {
    console.log('anonymous function expression');
  };
}

函數聲明的名稱和函數體都會被提高

function example() {
  superPower(); // => Flying

  function superPower() {
    console.log('Flying');
  }
}

比較和等號

優先使用 === 和 !== 而不是 == 和 !=

//good
if(a===1){}

使用簡寫

// bad
if (name !== '') {
  // ...stuff...
}

// good
if (name) {
  // ...stuff...
}

// bad
if (collection.length > 0) {
  // ...stuff...
}

// good
if (collection.length) {
  // ...stuff...
}

三元運算符通寫在一行

// badjava

const foo = maybe1 > maybe2
  ? "bar"
  : value1 > value2 ? "baz" : null;

// split into 2 separated ternary expressions
const maybeNull = value1 > value2 ? 'baz' : null;

// better
const foo = maybe1 > maybe2
  ? 'bar'
  : maybeNull;

// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

避免沒必要要的三元運算符

// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;

// good
const foo = a || b;
const bar = !!c;
const baz = !c;

混合運算時,儘可能用括號,易懂

//bad
if(a || b && c){
    //...
}
//good
if(a || (b && c)){
    //...
}

代碼塊

用大括號包裹全部的多行代碼塊

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

條件語句

條件語句,換行將運算符放在最前面

// badgit

if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
  thing1();
}
//good
if (
    (foo === 123 || bar === 'abc') 
    && doesItLookGoodWhenItBecomesThatLong() 
    && isThisReallyHappening()
    ) {
  thing1();
}

註釋

- 使用 /** ... */ 做爲多行註釋
- 使用 // 做爲單行註釋 ,上方空一行
- 使用 // FIXME: 標註問題
- 使用 // TODO: 標註問題的解決方式

逗號

- 行首逗號:不須要
- 結尾的逗號: 須要

分號

- 別省略分號

類型轉換

字符串

// bad
const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"

// bad
const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()

// bad
const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string

// good
const totalScore = String(this.reviewScore);

數字

let inputValue= 4;

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue >> 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);

布爾

const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// good
const hasAge = !!age;

命名規則

- 避免單字母命名。命名應具有描述性
- 使用駝峯式命名對象、函數和實例
- 使用ES6命名構造函數或類
class  User {
    constructor(options) {
        this.name = options.name;
    }
}
let good = new User({
    name:"yup"
});
- 使用下劃線 _ 開頭命名私有屬性
- 使用箭頭函數避免this引用錯誤
//bad 
function test(){
    let self = this;
    return function(){
        console.log(self);
    }
}
//good
function test(){
    return ()=>{
        console.log(this);
    }
}
- 文件只輸出一個類,文件名必須和類名徹底保持一致
// 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';

存取器

- 使用好get、set
- is、has
- 保持一致
// bad
dragon.age();

// good
dragon.getAge();
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}

事件

// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {
  // do something with listingId
});    
// good
$(this).trigger('listingUpdated', { listingId : listing.id });

...

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

jQuery

使用 $ 做爲存儲 jQuery 對象的變量名前綴

// bad
const sidebar = $('.sidebar');

// good
const $sidebar = $('.sidebar');

緩存 jQuery 查詢

const $sidebar = $('.sidebar');

對 DOM 查詢使用層疊

$('.sidebar ul')
$('.sidebar > ul')

對有做用域的 jQuery 對象查詢使用 find

// bad
$('ul', '.sidebar').hide();
// good
$sidebar.find('ul').hide();


參考:
https://github.com/airbnb/javascript
相關文章
相關標籤/搜索