JS.next

JavaScriptの最新実装情報を追うブログ

new.targetメタプロパティについて

概要

「new.target」とは、ES2015で導入されたビルトインクラスのサブクラスを作る上で欠かせない存在である[[newTarget]]を取得するためのメタプロパティである。


従来の問題点

ES5まではArrayのようなビルトインクラスを適切に継承したサブクラスを作ることができなかった。
ES2015からのプロトタイプ設定機能を使うと可能であり、このようになる。

class Stack extends Array {
  constructor( ...args ) {
    var stack = new Array( ...args )
    return Object.setPrototypeOf( stack, Stack.prototype )
  }
  clear() { this.length = 0 }
}


しかし毎回このように書かないといけないのはスマートではない。
できればこの様に書きたいものである。

class Stack extends Array {
  constructor( ...args ) {
    super( ...args )
  }
  clear() { this.length = 0 }
}


ここで、「new Stack( ...args )」とした時の動作を考えてみる。
「super( ...args )」がStackのプロトタイプを呼び、返り値をthisに設定する動作とすると、
結果は「Array(...args)」としたのに等しい。
当然それではStack.prototypeがプロトタイプの配列を得ることはできない。

ではどうであればいいのかというと、『何がnew演算子のターゲットになったのか』という情報をArrayまで伝播できればいいのである。
そこで生まれたのが[[newTarget]]であって、「new Stack()」とすると[[newTarget]]をStackとしてStackが呼ばれる。
そして[[newTarget]]はsuperで伝えられるので、「super(...args)」で呼ばれるArrayでの[[newTarget]]もStackになる。
これでその時のArrayはStack.prototypeをプロトタイプとした配列を作って返すことができるようになるのである。

ちなみに、上記コードのconstructorはclass構文でconstructorを省いた場合のデフォルトの動作と同等なので、さらにこの様に書ける。

class Stack extends Array {
  clear() { this.length = 0 }
}


他のいくつかのビルトインクラスもこの仕組みで簡単に継承が可能となっている。


[[newTarget]]を取得する [4.5.86]

[[newTarget]]は「new.target」という表記で取得できる。
例:

class B {
 constructor() { 
    console.log( new.target == C )
  }
}
class C extends B { }

new C  //// true


実装されるバージョン

V8 4.3.19(Arrayだけの限定対応) - 4.5.86(完了) 4.8終期(ビルトインコンストラクタのサブクラス化に関するBug fix)