JS.next

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

[[newTarget]]について

概要

[[newTarget]]とはES6から導入される概念で、ビルドインクラスのサブクラスを作る上で欠かせない存在である。


従来の問題点

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

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()」とされると呼ばれたStackの[[newTarget]]はStackになる。
そして[[newTarget]]はsuperで伝えられるので、「super(...args)」で呼ばれるArrayでの[[newTarget]]もStackになる。
これでその時のArrayはStack.prototypeをプロトタイプとした配列を作って返すことができるようになるのである。

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

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


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


[[newTarget]]を取得する  (未実装)

[[newTarget]]は「new.target」から取得できる。
例:

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

new C  //// true


実装されるバージョン

V8 4.3.19(Arrayだけの限定対応)