From dc8acd5472f9970ed9e1f13123a8b98bbec3d590 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Tue, 1 Oct 2024 04:22:00 -0400 Subject: [PATCH] Add example for Reflect.construct newTarget parameter (#35996) --- .../global_objects/reflect/construct/index.md | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/javascript/reference/global_objects/reflect/construct/index.md b/files/en-us/web/javascript/reference/global_objects/reflect/construct/index.md index 317c6fa4af98454..0a43ab5aa80155a 100644 --- a/files/en-us/web/javascript/reference/global_objects/reflect/construct/index.md +++ b/files/en-us/web/javascript/reference/global_objects/reflect/construct/index.md @@ -25,7 +25,7 @@ Reflect.construct(target, argumentsList, newTarget) - `argumentsList` - : An [array-like object](/en-US/docs/Web/JavaScript/Guide/Indexed_collections#working_with_array-like_objects) specifying the arguments with which `target` should be called. - `newTarget` {{optional_inline}} - - : The value of [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target) operator, which usually specifies the prototype of the returned object. If `newTarget` is not present, its value defaults to `target`. + - : The value of the [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target) expression inside `target`. Defaults to `target`. Generally ([see example](#changing_new.target)), `target` specifies the _logic_ to initialize the object, while `newTarget.prototype` specifies the _prototype_ of the constructed object. ### Return value @@ -76,6 +76,74 @@ d instanceof Date; // true d.getFullYear(); // 1776 ``` +### Changing new.target + +If `newTarget` is passed, it changes the value of `new.target` inside the constructor. The constructed object will be an instance of `newTarget`, not `target`. + +```js +function OneClass() { + console.log("OneClass executed"); + console.log(`new.target is ${new.target.name}`); +} + +function OtherClass() { + console.log("OtherClass executed"); + console.log(`new.target is ${new.target.name}`); +} + +const obj1 = Reflect.construct(OneClass, []); +// Logs: +// OneClass executed +// new.target is OneClass +console.log(obj1 instanceof OneClass); // true + +const obj2 = Reflect.construct(OneClass, [], OtherClass); +// Logs: +// OneClass executed +// new.target is OtherClass +console.log(obj2 instanceof OtherClass); // true +console.log(obj2 instanceof OneClass); // false +``` + +Of course, there's no strong guarantee about the prototype chain of the constructed object, as it depends on the constructor's implementation. For example, if the `target` constructor returns an object, then that object will be the constructed object, regardless of the `newTarget` value. If `target` is a proxy with a `construct` trap, then the trap fully controls the construction process. + +```js +function OneClass() { + return { name: "one" }; +} + +function OtherClass() { + return { name: "other" }; +} + +const obj1 = Reflect.construct(OneClass, [], OtherClass); +console.log(obj1.name); // 'one' +console.log(obj1 instanceof OneClass); // false +console.log(obj1 instanceof OtherClass); // false +``` + +A valid `new.target` should be a constructor function with a [`prototype`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype) property, but the latter is not enforced. If the `prototype` property's value is not an object, the initialized object will inherit from `Object.prototype`. + +```js +function OneClass() { + console.log("OneClass executed"); + console.log(`new.target is ${new.target.name}`); +} + +function OtherClass() { + console.log("OtherClass executed"); + console.log(`new.target is ${new.target.name}`); +} + +OtherClass.prototype = null; + +const obj = Reflect.construct(OneClass, [], OtherClass); +// Logs: +// OneClass executed +// new.target is OtherClass +console.log(Object.getPrototypeOf(obj) === Object.prototype); // true +``` + ### Reflect.construct() vs. Object.create() Prior to the introduction of `Reflect`, objects could be constructed using an arbitrary combination of constructors and prototypes using {{jsxref("Object.create()")}}.