【譯】js代碼規範-最佳實踐

原文地址:JavaScript Clean Code - Best Practices 原做者:Milos Proticjavascript


介紹

若是你關心代碼的自己以及編寫方式,而只是擔憂代碼是否有效的,你能夠說你實踐而且關心代碼的規範性。專業的開發人員老是會考慮到本身便於未來還能可讀和其餘的團隊人員,並非僅僅考慮到運行的結果。你寫的任何代碼並非只寫一次,總會有其餘的開發人員來作你寫的代碼,若是你寫的不規範,而他則會痛苦不堪。但願這我的不是你。java

整體來講,規範性的代碼能夠定義爲不言自明,易於人理解且易於更改或者擴展的編寫方式。es6

當你接到別人寫的代碼,第一個印象就是「這個代碼什麼玩意兒」,那你問本身,你還會有多少次願意繼續作別人寫的代碼呢?編程

"WTF is that?"bash

"WTF did you do here?"編程語言

"WTF is this for?" (這個就不翻譯了,本身感覺下)函數

下圖就是表明以上所述內容的流行圖片 post

image

自配的WTF表情包

引用Robert C.Martin的一句話,這話應該會讓你思考編寫方式。測試

Even bad code can function. But if the code isn’t clean, it can bring a development organization to its knees.ui

在本文中,重點將在於js,這些原則也能用於其餘的編程語言。

一、強類型檢查 === 代替 ==

0 == false // true
0 === false // false
2 == "2" // true
2 === "2" // false

// 例子
const value = "500";
if (value === 500) {
  console.log(value);
  // 沒打印出來
}

if (value === "500") {
  console.log(value);
  // 打印出來了
}
複製代碼

二、變量

  • 給變量命名時,應該要使變量名具備表明意圖的象徵,令人易於搜索而且容易理解。

Bad:

let daysSLV = 10;
let y = new Date().getFullYear();

let ok;
if (user.age > 30) {
  ok = true;
}
//本人解釋:y,ok這些什麼玩意兒呢,30又是什麼意思呢?
複製代碼

Good:

const MAX_AGE = 30; //哦,是最大的年齡
let daysSinceLastVisit = 10;
let currentYear = new Date().getFullYear();//哦,是當前年份

...

const isUserOlderThanAllowed = user.age > MAX_AGE;
複製代碼
  • 不要在變量名中增長不必額外的單詞

Bad:

let nameValue;
let theProduct;
複製代碼

Good:

let name;
let product;
複製代碼
  • 不要強制記憶變量名的上下文

Bad:

const users = ["John", "Marco", "Peter"];
users.forEach(u => {
  doSomething();
  doSomethingElse();
  // ...
  // ...
  // ...
  // ...
  // 這u什麼玩意兒呢?
  register(u);
});
複製代碼

Good:

const users = ["John", "Marco", "Peter"];
users.forEach(user => {
  doSomething();
  doSomethingElse();
  // ...
  // ...
  // ...
  // ...
  register(user);
});
複製代碼
  • 變量名不要加上下文重複的單詞

Bad:

const user = {
  userName: "John",
  userSurname: "Doe",
  userAge: "28"
};

...

user.userName;
複製代碼

Good:

const user = {
  name: "John",
  surname: "Doe",
  age: "28"
};

...

user.name;
複製代碼

三、函數

  • 函數名應該是動詞或者短語,表明某種行爲,描述它們在作什麼

Bad:

function notif(user) {
  // implementation
}
複製代碼

Good:

function notifyUser(emailAddress) {
  // implementation
}
複製代碼
  • 避免使用大量的參數,理想的狀況就是用兩個或者更少的參數。參數越少,測試就越容易

Bad:

function getUsers(fields, fromDate, toDate) {
  // implementation
}
複製代碼

Good:

function getUsers({ fields, fromDate, toDate }) {
  // implementation
}

getUsers({
  fields: ['name', 'surname', 'email'],
  fromDate: '2019-01-01',
  toDate: '2019-01-18'
}); 
複製代碼
  • 函數應該使用默認參數,而不是條件語句

Bad:

function createShape(type) {
  const shapeType = type || "cube";
  // ...
}
複製代碼

Good:

function createShape(type = "cube") {
  // ...
}
複製代碼

(這個的緣由,可能有些人不明白的,在此放連接阮一峯es6入門-函數參數的默認值

  • 一個函數應該作一件事,避免在一個函數中執行多個操做。

Bad:

function notifyUsers(users) {
  users.forEach(user => {
    const userRecord = database.lookup(user);
    if (userRecord.isVerified()) {
      notify(user);
    }
  });
}
複製代碼

Good:

function notifyVerifiedUsers(users) {
  users.filter(isUserVerified).forEach(notify);
}

function isUserVerified(user) {
  const userRecord = database.lookup(user);
  return userRecord.isVerified();
}
複製代碼
  • 使用Object.assign設置默認對象。

Bad:

const shapeConfig = {
  type: "cube",
  width: 200,
  height: null
};

function createShape(config) {
  config.type = config.type || "cube";
  config.width = config.width || 250;
  config.height = config.width || 250;
}

createShape(shapeConfig);
複製代碼

Good:

const shapeConfig = {
  type: "cube",
  width: 200
  // Exclude the 'height' key
};

function createShape(config) {
  config = Object.assign(
    {
      type: "cube",
      width: 250,
      height: 250
    },
    config
  );

  ...
}

createShape(shapeConfig);
複製代碼
  • 不要使用標誌記做爲參數,由於它們告訴你該函數正在作的比它應該作的更多。

Bad:

function createFile(name, isPublic) {
  if (isPublic) {
    fs.create(`./public/${name}`);
  } else {
    fs.create(name);
  }
}
複製代碼

Good:

function createFile(name) {
  fs.create(name);
}

function createPublicFile(name) {
  createFile(`./public/${name}`);
}
複製代碼
  • 不要污染全局變量。若是須要擴展示有對象,請使用ES6類和繼承,而不是在現有對象的原型鏈上建立函數

Bad:

Array.prototype.myFunc = function myFunc() {
  // implementation
};
複製代碼

Good:

class SuperArray extends Array {
  myFunc() {
    // implementation
  }
}
複製代碼

四、條件語句

  • 避免負面條件

Bad:

function isUserNotBlocked(user) {
  // implementation
}

if (!isUserNotBlocked(user)) {
  // implementation
}
複製代碼

Good:

function isUserBlocked(user) {
  // implementation
}

if (isUserBlocked(user)) {
  // implementation
}
複製代碼
  • 使用條件語句儘可能短點。這多是微不足道的,但值得一提。此方法僅用於布爾值,而且若是您肯定該值不是未定義的或爲null。

Bad:

if (isValid === true) {
  // do something...
}

if (isValid === false) {
  // do something...
}
複製代碼

Good:

if (isValid) {
  // do something...
}

if (!isValid) {
  // do something...
}
複製代碼
  • 儘量避免switch分支,請改用多態和繼承。

Bad:

class Car {
  // ...
  getMaximumSpeed() {
    switch (this.type) {
      case "Ford":
        return this.someFactor() + this.anotherFactor();
      case "Mazda":
        return this.someFactor();
      case "McLaren":
        return this.someFactor() - this.anotherFactor();
    }
  }
}
複製代碼

Good:

class Car {
  // ...
}

class Ford extends Car {
  // ...
  getMaximumSpeed() {
    return this.someFactor() + this.anotherFactor();
  }
}

class Mazda extends Car {
  // ...
  getMaximumSpeed() {
    return this.someFactor();
  }
}

class McLaren extends Car {
  // ...
  getMaximumSpeed() {
    return this.someFactor() - this.anotherFactor();
  }
}
複製代碼

五、Es6類

  • 類是JavaScript中的新語法糖,跟原型對象同樣,只是它如今看起來不一樣,你應該更喜歡它們而不是ES5的使用構造函數。

Bad:

const Person = function(name) {
  if (!(this instanceof Person)) {
    throw new Error("Instantiate Person with `new` keyword");
  }

  this.name = name;
};

Person.prototype.sayHello = function sayHello() { /**/ };

const Student = function(name, school) {
  if (!(this instanceof Student)) {
    throw new Error("Instantiate Student with `new` keyword");
  }

  Person.call(this, name);
  this.school = school;
};

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.printSchoolName = function printSchoolName() { /**/ };
複製代碼

Good:

class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    /* ... */
  }
}

class Student extends Person {
  constructor(name, school) {
    super(name);
    this.school = school;
  }

  printSchoolName() {
    /* ... */
  }
}
複製代碼
  • 使用方法連接,許多庫如jQuery和Lodash都使用這種模式。所以,您的代碼將不那麼冗長。在你的類中,只需在每一個函數的末尾返回它,你就能夠將更多的類方法連接到它上面。

Bad:

class Person {
  constructor(name) {
    this.name = name;
  }

  setSurname(surname) {
    this.surname = surname;
  }

  setAge(age) {
    this.age = age;
  }

  save() {
    console.log(this.name, this.surname, this.age);
  }
}

const person = new Person("John");
person.setSurname("Doe");
person.setAge(29);
person.save();
複製代碼

Good:

class Person {
  constructor(name) {
    this.name = name;
  }

  setSurname(surname) {
    this.surname = surname;
    // Return this for chaining
    return this;
  }

  setAge(age) {
    this.age = age;
    // Return this for chaining
    return this;
  }

  save() {
    console.log(this.name, this.surname, this.age);
    // Return this for chaining
    return this;
  }
}

const person = new Person("John")
    .setSurname("Doe")
    .setAge(29)
    .save();
複製代碼

六、常規的避免

通常來講,儘可能不要重複本身,就是說不該該編寫重複的代碼,也不要在你身後留下尾巴,好比未使用的函數和死代碼。 因爲各類緣由,你最終可能會有重複的代碼。好比,你可能有兩個略有不一樣的東西,它們有許多共同之處,有時期限不足的迫使你建立包含幾乎一樣代碼的單獨函數。 關於死代碼,這正如它的名字。它沒有作任何事情,由於在某些開發階段,你已經決定再也不用它,您應該在代碼庫中搜索這些不須要的函數和代碼塊並刪除。 我建議你,一旦你決定再也不須要它,就立刻刪除它, 以防你之後可能會忘記它的用途。 這只是改進代碼所能作的小部分。 在我看來,這裏所說的原則是人們常常不遵循的原則。 他們嘗試但老是因各類緣由而沒成功。 也許項目一開始時,代碼是整潔乾淨,但在最後期限時,原則常常被忽略並轉移到「TODO」或「REFACTOR」部分。 到那時,您的客戶寧願讓您知足截止日期,而不是規範的代碼。 到此爲止! 感謝你閱讀而且但願在下一篇文章看到你。

相關文章
相關標籤/搜索