分析JavaScript代碼整潔之道

本篇內(nèi)容主要講解“分析JavaScript代碼整潔之道”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“分析JavaScript代碼整潔之道”吧!

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),江津企業(yè)網(wǎng)站建設(shè),江津品牌網(wǎng)站建設(shè),網(wǎng)站定制,江津網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,江津網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

1. 用命名的變量代替數(shù)組下標(biāo)

// bad
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(
  // 下標(biāo)1,2不易于理解
  address.match(cityZipCodeRegex)[1],
  address.match(cityZipCodeRegex)[2]
);
// good
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
// 使用數(shù)組解構(gòu)更好的命名變量
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

2. 函數(shù)的參數(shù)最好<=2個(gè),盡量避免3個(gè)。

如果有很多參數(shù)就利用object傳遞,并使用解構(gòu)。

3. 一個(gè)函數(shù)只做一件事。

好處在于compose, test, and reason about。

4. 不要自行擴(kuò)展原型

如果想擴(kuò)展原型,可以先繼承再添加方法,防止污染。

// bad
Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};
// good
class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));
  }
}

5. 用多態(tài)來代替條件語句

// bad
if (type === 'text') {
    // do something
} else if (type === 'select') {
    // do something else
}

個(gè)人寫這種代碼的一種常用方式是:

const control = {
    text: {
        mapper() {},
        restore(){},
        name: 'this is a text field',
    },
    select: {
        mapper() {},
        restore(){},
        name: 'this is a select field',
    }
}
control[type].mapper();

實(shí)際上就是多態(tài)(polymorphism),也可以考慮用class的方式,大概這樣:

class Field {
    ...
}
class TextField extends Field {
    mapper(){}
    restore(){}
    name = 'this is a text field';
}
class SelectField extends Field {
    mapper(){}
    restore(){}
    name = 'this i```s a select field';
}
  1. 使用getter和setter函數(shù)。

// bad
function makeBankAccount() {
  // ...
  return {
    balance: 0
    // ...
  };
}
const account = makeBankAccount();
account.balance = 100;
// good
function makeBankAccount() {
  // this one is private
  let balance = 0;
  // a "getter", made public via the returned object below
  function getBalance() {
    return balance;
  }
  // a "setter", made public via the returned object below
  function setBalance(amount) {
    // ... validate before updating the balance
    balance = amount;
  }
  return {
    // ...
    getBalance,
    setBalance
  };
}
const account = makeBankAccount();
account.setBalance(100);

你可以在getter和setter里面做很多事情而不需要修改每一個(gè).balance的地方。

7. Prefer composition over inheritance

盡量用組合來代替繼承,什么情況下用繼承:

Your inheritance represents an "is-a" relationship and not a "has-a" relationship (Human->Animal vs. User->UserDetails).
You can reuse code from the base classes (Humans can move like all animals).
You want to make global changes to derived classes by changing a base class. (Change the caloric expenditure of all animals when they move).

8. SOLID

Single Responsibility Principle 單一職責(zé)原則

There should never be more than one reason for a class to change,一個(gè)類被改變的原因數(shù)量應(yīng)該盡可能降低。如果一個(gè)類中---功能太多,當(dāng)你修改其中一點(diǎn)時(shí)會(huì)無法估量任何引用該類的模塊所受到的影響。

Open/Closed Principle 開放封閉原則

用戶可以在不修改內(nèi)部實(shí)現(xiàn)的前提下自行擴(kuò)展功能。例如有一個(gè)Http模塊,內(nèi)部會(huì)根據(jù)環(huán)境判斷用哪個(gè)adaptor。如果用戶要添加adaptor就必須修改Http模塊。

// bad
class AjaxAdapter extends Adapter {
  constructor() {
    super();
    this.name = "ajaxAdapter";
  }
}
class NodeAdapter extends Adapter {
  constructor() {
    super();
    this.name = "nodeAdapter";
  }
}
class HttpRequester {
  constructor(adapter) {
    this.adapter = adapter;
  }
  fetch(url) {
    if (this.adapter.name === "ajaxAdapter") {
      return makeAjaxCall(url).then(response => {
        // transform response and return
      });
    } else if (this.adapter.name === "nodeAdapter") {
      return makeHttpCall(url).then(response => {
        // transform response and return
      });
    }
  }
}
function makeAjaxCall(url) {
  // request and return promise
}
function makeHttpCall(url) {
  // request and return promise
}
// good
class AjaxAdapter extends Adapter {
  constructor() {
    super();
    this.name = "ajaxAdapter";
  }
  request(url) {
    // request and return promise
  }
}
class NodeAdapter extends Adapter {
  constructor() {
    super();
    this.name = "nodeAdapter";
  }
  request(url) {
    // request and return promise
  }
}
class HttpRequester {
  constructor(adapter) {
    this.adapter = adapter;
  }
  fetch(url) {
    return this.adapter.request(url).then(response => {
      // transform response and return
    });
  }
}

Liskov Substitution Principle 里式替換原則

父類和子類應(yīng)該可以被交換使用而不會(huì)出錯(cuò)。

// bad
class Rectangle {
  constructor() {
    this.width = 0;
    this.height = 0;
  }
  setColor(color) {
    // ...
  }
  render(area) {
    // ...
  }
  setWidth(width) {
    this.width = width;
  }
  setHeight(height) {
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}
class Square extends Rectangle {
  setWidth(width) {
    this.width = width;
    this.height = width;
  }
  setHeight(height) {
    this.width = height;
    this.height = height;
  }
}
function renderLargeRectangles(rectangles) {
  rectangles.forEach(rectangle => {
    rectangle.setWidth(4);
    rectangle.setHeight(5);
    const area = rectangle.getArea(); // BAD: Returns 25 for Square. Should be 20.
    rectangle.render(area);
  });
}
const rectangles = [new Rectangle(), new Rectangle(), new Square()];
renderLargeRectangles(rectangles);

上面的Rectangle不能直接替換Square,因?yàn)闀?huì)導(dǎo)致計(jì)算面積錯(cuò)誤,考慮將計(jì)算面積的方法抽象出來:

class Shape {
  setColor(color) {
    // ...
  }
  render(area) {
    // ...
  }
}
class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}
class Square extends Shape {
  constructor(length) {
    super();
    this.length = length;
  }
  getArea() {
    return this.length * this.length;
  }
}
function renderLargeShapes(shapes) {
  shapes.forEach(shape => {
    const area = shape.getArea();
    shape.render(area);
  });
}
const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new Square(5)];
renderLargeShapes(shapes);

Interface Segregation Principle 接口隔離原則

Clients should not be forced to depend upon interfaces that they do not use。舉例來說,一個(gè)功能模塊需要設(shè)計(jì)必須傳的參數(shù)和可選參數(shù),不應(yīng)該強(qiáng)迫用戶使用可選參數(shù)。

Dependency Inversion Principle 依賴注入原則

// bad
class InventoryRequester {
  constructor() {
    this.REQ_METHODS = ["HTTP"];
  }
  requestItem(item) {
    // ...
  }
}
class InventoryTracker {
  constructor(items) {
    this.items = items;
    // BAD: We have created a dependency on a specific request implementation.
    // We should just have requestItems depend on a request method: `request`
    this.requester = new InventoryRequester();
  }
  requestItems() {
    this.items.forEach(item => {
      this.requester.requestItem(item);
    });
  }
}
const inventoryTracker = new InventoryTracker(["apples", "bananas"]);
inventoryTracker.requestItems();

上面例子在于,InventoryTracker內(nèi)部實(shí)例化了InventoryRequester,也就意味著high-level的模塊需要知道low-level模塊的細(xì)節(jié)(比如實(shí)例化InventoryRequester需要知道它的構(gòu)造參數(shù)等,或者說需要import該模塊,造成耦合)。

// good
class InventoryTracker {
  constructor(items, requester) {
    this.items = items;
    this.requester = requester;
  }
  requestItems() {
    this.items.forEach(item => {
      this.requester.requestItem(item);
    });
  }
}
class InventoryRequesterV1 {
  constructor() {
    this.REQ_METHODS = ["HTTP"];
  }
  requestItem(item) {
    // ...
  }
}
class InventoryRequesterV2 {
  constructor() {
    this.REQ_METHODS = ["WS"];
  }
  requestItem(item) {
    // ...
  }
}
// By constructing our dependencies externally and injecting them, we can easily
// substitute our request module for a fancy new one that uses WebSockets.
const inventoryTracker = new InventoryTracker(
  ["apples", "bananas"],
  new InventoryRequesterV2()
);
inventoryTracker.requestItems();

直接傳入low-level的實(shí)例而不需要考慮它是如何被實(shí)例化的,high-level只需要依賴抽象的接口就可以完成對子模塊的調(diào)用。

9. 注釋

Comments are an apology, not a requirement. Good code mostly documents itself. 好的代碼是自解釋的。

你會(huì)經(jīng)常地遇到 bug 和其它一些問題。這可能會(huì)讓人沮喪,但你要盡量保持冷靜,并系統(tǒng)地去思考。記住實(shí)踐是解決問題的最佳方法。

到此,相信大家對“分析JavaScript代碼整潔之道”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

當(dāng)前文章:分析JavaScript代碼整潔之道
網(wǎng)站地址:http://www.muchs.cn/article4/jsosie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)小程序開發(fā)、做網(wǎng)站、品牌網(wǎng)站制作、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)