Deep JavaScript
本書をサポートしてください: 購入する または 寄付する
(広告。ブロックしないでください。)

14 クラスのインスタンスのコピー: .clone() 対コピーコンストラクタ



この章では、2つのクラスインスタンスのコピーを実装する技術について説明します。

14.1 .clone() メソッド

この手法では、コピーされるインスタンスを持つクラスごとに .clone() メソッドを1つ導入します。this のディープコピーを返します。以下の例はクローン可能な 3 つのクラスを示しています。

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 などの静的言語で普及しています。ここでは、static は使用されるバージョンをコンパイル時に選択することを意味します。

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);

スタティックファクトリメソッドはコンストラクタの代替であり、目的の機能を直接呼び出すことができるため、この場合に適しています。(ここでは、static はこれらのファクトリメソッドがクラスメソッドであることを意味します。)

次の例では、3 つのクラス 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 謝辞