🤖

instanceof をごまかす

2022/03/04に公開

2つの方法を紹介します。

Object.setPrototypeOf

実際にはごまかすというよりは instanceof は MDN にあるとおり

instanceof 演算子は、あるコンストラクターの prototype プロパティが、あるオブジェクトのプロトタイプチェーンの中のどこかに現れるかどうかを検査します。

だけなので、納得感のある挙動なのですが、クラスベースの考え方だとあとから継承ツリーになにかを入れられるというのがやや違和感のある挙動なのでメモしておきます。

JavaScript には instanceof という二項演算子があります。左辺に値を、右辺にクラスを渡すと値がクラスのインスタンスかどうかを boolean で返してくれます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/instanceof

class Foo {}
const foo = new Foo();
console.log(foo instanceof Foo); // true

instanceof 演算子は prototype に依存するので、Object.setPrototypeOf を使うことで挙動を変更できます。

次の例では obj はもともと Foo のインスタンスではないので、一回めの obj instanceof Foofalse を返します。しかし Object.setPrototypeOf(obj, foo); したあとの obj instanceof Footrue を返します。

class Foo {}
const foo = new Foo();

const obj = {};

console.log(obj instanceof Foo); // false

Object.setPrototypeOf(obj, foo);

console.log(obj instanceof Foo); // true

Symbol.hasInstance

JavaScript には Symbol.hasInstance という Well-known Symbol があります。これを使うとクラスが instanceof 演算子の右のオペランドになったとき、どのように真偽値を返すかを制御できます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance

class Foo {
  static [Symbol.hasInstance]() {
    return true;
  }
}

const obj = {};

console.log(obj instanceof Foo); // true

Discussion