Cos’è “new.target”?

Le specifiche di ECMAScript 2015 menzionano la parola chiave (o le parole?) New.target esattamente 3 volte – 1 volta in 14.2.3 :

Normalmente, Contains non guarda nella maggior parte dei moduli di funzione. Tuttavia, Contains viene utilizzato per rilevare new.target , questo e l’uso super all’interno di ArrowFunction.

e due volte in 14.2.16 :

Una ArrowFunction non definisce binding locali per argomenti, super, this o new.target . Qualsiasi riferimento agli argomenti, super, this o new.target all’interno di ArrowFunction deve risolversi in un binding in un ambiente che racchiude lessicalmente

La MDN lo menziona, ma è molto vago e la pagina è incompleta.

Babel non sembra supportarlo. Ho avuto errori di syntax durante il tentativo di utilizzare new.target in una funzione (freccia o altro).

Cos’è e come dovrebbe essere usato?

Non l’hai trovato nelle specifiche perché nelle definizioni di syntax è scritto con spazi vuoti, come new . target new . target . Il nome dell’espressione è NewTarget , e troverai quel termine un po ‘di volte.

NewTarget è la prima delle cosiddette proprietà meta e può essere trovata in §12.3.8.

Il suo unico scopo è quello di recuperare il valore corrente del valore [[NewTarget]] dell’ambiente di funzionamento corrente (non-freccia). È un valore che viene impostato quando viene chiamata una funzione (molto simile a this associazione) e in base al §8.1.1.3 Record di ambiente della funzione :

Se questo Record Ambiente è stato creato dal metodo interno [[Costrutto]] , [[NuovoTarget]] è il valore del parametro [[Costrutto]] newTarget . Altrimenti, il suo valore undefined è undefined .

Quindi, per prima cosa, finalmente ci consente di rilevare se una funzione è stata chiamata come costruttore o no.

Ma questo non è il suo vero scopo. Allora cos’è allora? Fa parte del modo in cui le classi ES6 non sono solo zucchero sintattico e in che modo ci consentono di ereditare dagli oggetti incorporati. Quando si chiama un costruttore di class tramite la new X , this valore non è ancora stato inizializzato – l’object non è ancora stato creato quando viene immesso il corpo del costruttore. Viene creato dal super costruttore durante la chiamata a super() (che è necessario quando devono essere creati slot interni). Tuttavia, l’istanza dovrebbe ereditare dal .prototype del costruttore originariamente chiamato, ed è qui che entra in gioco newTarget . Sostiene il costruttore “più esterno” che ha ricevuto la new chiamata durante le invocazioni super() . Puoi seguirlo fino in fondo nelle specifiche, ma in fondo è sempre il nuovo newTarget non il costruttore attualmente eseguito che viene passato nella procedura OrdinaryCreateFromConstructor – ad esempio nel passaggio 5 di §9.2.2 [[Costruisci]] per l’utente funzioni definite.

Testo lungo, forse un esempio è più adatto:

 class Parent { constructor() { // implicit (from the `super` call) // new.target = Child; // implicit (because `Parent` doesn't extend anything): // this = Object.create(new.target.prototype); console.log(new.target) // Child! } } class Child extends Parent { constructor() { // `this` is uninitialised (and would throw if accessed) // implicit (from the `new` call): // new.target = Child super(); // this = Reflect.construct(Parent, [], new.target); console.log(this); } } new Child; 

È principalmente inteso come un modo migliore per rilevare quando un costruttore viene chiamato senza new .

Da http://www.2ality.com/2015/02/es6-classs-final.html :

new.target è un parametro implicito che tutte le funzioni hanno. È al costruttore che chiama ciò che è per le chiamate di metodo.

Quindi posso scrivere:

 function Foo() { if (!new.target) throw "Foo() must be called with new"; ... } 

Ci sono più dettagli su come funziona e più contesti in cui è utile, ma lo lasceremo qui.

Per alcune note di incontro riguardanti new.target , vedere https://esdiscuss.org/notes/2015-01-27 .