深入 JavaScript
請支持這本書:購買捐款
(廣告,請不要封鎖。)

14 複製類別實例:.clone() 與複製建構函式



在本章中,我們將探討兩種實作類別實例複製的技術

14.1 .clone() 方法

此技術會為每個要複製實例的類別,引入一個方法 .clone()。它會傳回 this 的深度複製。下列範例顯示了三個可以複製的類別。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  clone() {
    return new Point(this.x, this.y);
  }
}
class Color {
  constructor(name) {
    this.name = name;
  }
  clone() {
    return new Color(this.name);
  }
}
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);
    this.color = color;
  }
  clone() {
    return new ColorPoint(
      this.x, this.y, this.color.clone()); // (A)
  }
}

第 A 行展示了此技術的一個重要面向:複合實例屬性值也必須遞迴複製。

14.2 靜態工廠方法

複製建構函式是一種建構函式,它會使用目前類別的另一個實例來設定目前的實例。複製建構函式在 C++ 和 Java 等靜態語言中很受歡迎,因為您可以透過靜態重載提供多個版本的建構函式。在此,靜態表示在編譯時決定要使用哪個版本。

在 JavaScript 中,我們必須在執行時做出決定,這會導致程式碼不優雅

class Point {
  constructor(...args) {
    if (args[0] instanceof Point) {
      // Copy constructor
      const [other] = args;
      this.x = other.x;
      this.y = other.y;
    } else {
      const [x, y] = args;
      this.x = x;
      this.y = y;
    }
  }
}

以下是使用此類別的方法

const original = new Point(-1, 4);
const copy = new Point(original);
assert.deepEqual(copy, original);

靜態工廠方法是建構函式的替代方案,在這種情況下會運作得更好,因為我們可以直接呼叫所需的函數。(在此,靜態表示這些工廠方法是類別方法。)

在下列範例中,三個類別 PointColorColorPoint 各有一個靜態工廠方法 .from()

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  static from(other) {
    return new Point(other.x, other.y);
  }
}
class Color {
  constructor(name) {
    this.name = name;
  }
  static from(other) {
    return new Color(other.name);
  }
}
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);
    this.color = color;
  }
  static from(other) {
    return new ColorPoint(
      other.x, other.y, Color.from(other.color)); // (A)
  }
}

在第 A 行中,我們再次遞迴複製。

以下是 ColorPoint.from() 的運作方式

const original = new ColorPoint(-1, 4, new Color('red'));
const copy = ColorPoint.from(original);
assert.deepEqual(copy, original);

14.3 致謝