国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript代碼整潔之道

liaorio / 2977人閱讀

摘要:代碼整潔之道整潔的代碼不僅僅是讓人看起來舒服,更重要的是遵循一些規范能夠讓你的代碼更容易維護,同時降低幾率。另外這不是強制的代碼規范,就像原文中說的,。里式替換原則父類和子類應該可以被交換使用而不會出錯。注釋好的代碼是自解釋的。

JavaScript代碼整潔之道

整潔的代碼不僅僅是讓人看起來舒服,更重要的是遵循一些規范能夠讓你的代碼更容易維護,同時降低bug幾率。

原文clean-code-javascript,這里總結摘錄出個人覺得有幫助的地方,也加入了一些自己的理解(有些文字我感覺保留原文更好,所以直接copy了),其他還有很多點沒有列出來,感興趣可以去看原文。另外這不是強制的代碼規范,就像原文中說的,These are guidelines and nothing more
1. 用命名的變量代替數組下標
// bad
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,]+[,s]+(.+?)s*(d{5})?$/;
saveCityZipCode(
  // 下標1,2不易于理解
  address.match(cityZipCodeRegex)[1],
  address.match(cityZipCodeRegex)[2]
);
// good
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,]+[,s]+(.+?)s*(d{5})?$/;
// 使用數組解構更好的命名變量
const [, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);
2. 函數的參數最好<=2個,盡量避免3個。

如果有很多參數就利用object傳遞,并使用解構。

注意object array這些引用類型的值是mutable的。
3. 一個函數只做一件事。

好處在于compose, test, and reason about

4. 不要自行擴展原型

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

// 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. 用多態來代替條件語句
// bad
if (type === "text") {
    // do something
} else if (type === "select") {
    // do something else
}

我個人寫這種代碼的一種常用方式是:

const control = {
    text: {
        mapper() {},
        restore(){},
        name: "this is a text field",
    },
    select: {
        mapper() {},
        restore(){},
        name: "this is a select field",
    }
}

control[type].mapper();

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

class Field {
    ...
}

class TextField extends Field {
    mapper(){}
    restore(){}
    name = "this is a text field";
}

class SelectField extends Field {
    mapper(){}
    restore(){}
    name = "this is a select field";
}
6. 使用gettersetter函數。
// 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);

你可以在gettersetter里面做很多事情而不需要修改每一個.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 單一職責原則

There should never be more than one reason for a class to change,一個類被改變的原因數量應該盡可能降低。如果一個類中功能太多,當你修改其中一點時會無法估量任何引用該類的模塊所受到的影響。

Open/Closed Principle 開放封閉原則

用戶可以在不修改內部實現的前提下自行擴展功能。例如有一個Http模塊,內部會根據環境判斷用哪個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 里式替換原則

父類和子類應該可以被交換使用而不會出錯。

// 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,因為會導致計算面積錯誤,考慮將計算面積的方法抽象出來:

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。舉例來說,一個功能模塊需要設計必須傳的參數和可選參數,不應該強迫用戶使用可選參數。

Dependency Inversion Principle 依賴注入原則

原文:

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Abstractions should not depend upon details. Details should depend on abstractions.

// 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內部實例化了InventoryRequester,也就意味著high-level的模塊需要知道low-level模塊的細節(比如實例化InventoryRequester需要知道它的構造參數等,或者說需要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的實例而不需要考慮它是如何被實例化的,high-level只需要依賴抽象的接口就可以完成對子模塊的調用。

9. 注釋

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

參考:clean-code-javascript

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103083.html

相關文章

  • JavaScript代碼整潔之道

    摘要:概述在代碼整潔之道中提到的軟件工程原則,同樣適用于。我們在軟件工程方面的技術發展剛剛超過年,我們仍然在學習很多東西。不好好一個函數只做一件事目前這是軟件工程中最重要的原則。 概述 showImg(https://segmentfault.com/img/remote/1460000008066597?w=500&h=471); Robert C. Martin 在《代碼整潔之道》 中提...

    ideaa 評論0 收藏0
  • 代碼整潔之道

    摘要:在代碼整潔之道,提出一種軟件質量,可持續開發不僅在于項目架構設計,還與代碼質量密切相關,代碼的整潔度和質量成正比,一份整潔的代碼在質量上是可靠的,為團隊開發,后期維護,重構奠定了良好的基礎。 現在的軟件系統開發難度主要在于其復雜度和規模,客戶需求也不再像Winston Royce瀑布模型期望那樣在系統編碼前完成所有的設計滿足用戶軟件需求。在這個信息爆炸技術日新月異的時代,需求總是在不停...

    icattlecoder 評論0 收藏0
  • 代碼整潔之道 - 有意義的命名

    摘要:我們這里再介紹一下,朱重八家族的名字,都很有特點。取這樣的名字不是因為朱家是搞數學的,而是因為在元朝,老百姓如果不能上學和當官就沒有名字,只能以父母年齡相加或者出生的日期命名。所以說命名不僅僅是一種科學,更是一種藝術。 在小朱元璋出生一個月后,父母為他取了一個名字(元時慣例):朱重八,這個名字也可以叫做朱八八。我們這里再介紹一下,朱重八家族的名字,都很有特點。朱重八高祖名字:朱百六;朱...

    mengbo 評論0 收藏0
  • 代碼整潔之道 - 有意義的命名

    摘要:我們這里再介紹一下,朱重八家族的名字,都很有特點。取這樣的名字不是因為朱家是搞數學的,而是因為在元朝,老百姓如果不能上學和當官就沒有名字,只能以父母年齡相加或者出生的日期命名。所以說命名不僅僅是一種科學,更是一種藝術。 在小朱元璋出生一個月后,父母為他取了一個名字(元時慣例):朱重八,這個名字也可以叫做朱八八。我們這里再介紹一下,朱重八家族的名字,都很有特點。朱重八高祖名字:朱百六;朱...

    Cobub 評論0 收藏0

發表評論

0條評論

liaorio

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<