-
Notifications
You must be signed in to change notification settings - Fork 23.2k
Expand file tree
/
Copy pathindex.md
More file actions
236 lines (175 loc) · 7.92 KB
/
index.md
File metadata and controls
236 lines (175 loc) · 7.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
---
title: Reflect.construct()
short-title: construct()
slug: Web/JavaScript/Reference/Global_Objects/Reflect/construct
page-type: javascript-static-method
browser-compat: javascript.builtins.Reflect.construct
sidebar: jsref
---
The **`Reflect.construct()`** static method is like the {{jsxref("Operators/new", "new")}} operator, but as a function. It is equivalent to calling `new target(...args)`. It additionally allows to specify a different [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target) value.
{{InteractiveExample("JavaScript Demo: Reflect.construct()", "taller")}}
```js interactive-example
function func1(a, b, c) {
this.sum = a + b + c;
}
const args = [1, 2, 3];
const object1 = new func1(...args);
const object2 = Reflect.construct(func1, args);
console.log(object2.sum);
// Expected output: 6
console.log(object1.sum);
// Expected output: 6
```
## Syntax
```js-nolint
Reflect.construct(target, argumentsList)
Reflect.construct(target, argumentsList, newTarget)
```
### Parameters
- `target`
- : The target function to call.
- `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 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
A new instance of `target` (or `newTarget`, if present), initialized by `target` as a constructor with the given `argumentsList`.
### Exceptions
- {{jsxref("TypeError")}}
- : Thrown if `target` or `newTarget` is not a constructor, or if `argumentsList` is not an object.
## Description
`Reflect.construct()` provides the reflective semantic of a constructor call. That is, `Reflect.construct(target, argumentsList, newTarget)` is semantically equivalent to:
```js
new target(...argumentsList);
```
Note that when using the `new` operator, `target` and `newTarget` are always the same constructor — but `Reflect.construct()` allows you to pass a different [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target) value. Conceptually, `newTarget` is the function on which `new` was called, and `newTarget.prototype` will become the constructed object's prototype, while `target` is the constructor that is actually executed to initialize the object. For example, `new.target` may also be different from the currently executed constructor in class inheritance.
```js
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {}
new B(); // "B"
```
`Reflect.construct()` allows you to invoke a constructor with a variable number of arguments. (This is also possible with the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) in a normal constructor call.)
```js
const obj = new Foo(...args);
const obj = Reflect.construct(Foo, args);
```
`Reflect.construct()` invokes the `[[Construct]]` [object internal method](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#object_internal_methods) of `target`.
## Examples
### Using Reflect.construct()
```js
const d = Reflect.construct(Date, [1776, 6, 4]);
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()")}}.
```js
function OneClass() {
this.name = "one";
}
function OtherClass() {
this.name = "other";
}
const args = [];
const obj1 = Reflect.construct(OneClass, args, OtherClass);
const obj2 = Object.create(OtherClass.prototype);
OneClass.apply(obj2, args);
console.log(obj1.name); // 'one'
console.log(obj2.name); // 'one'
console.log(obj1 instanceof OneClass); // false
console.log(obj2 instanceof OneClass); // false
console.log(obj1 instanceof OtherClass); // true
console.log(obj2 instanceof OtherClass); // true
```
However, while the end result is the same, there is one important difference in the process. When using `Object.create()` and {{jsxref("Function.prototype.apply()")}}, the `new.target` operator will point to `undefined` within the function used as the constructor, since the `new` keyword is not being used to create the object. (In fact, it uses the [`apply`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply) semantic, not `construct`, although normal functions happen to operate nearly the same.)
When invoking `Reflect.construct()`, on the other hand, the `new.target` operator will point to the `newTarget` parameter if supplied, or `target` if not.
```js
function OneClass() {
console.log("OneClass");
console.log(new.target);
}
function OtherClass() {
console.log("OtherClass");
console.log(new.target);
}
const obj1 = Reflect.construct(OneClass, args);
// Logs:
// OneClass
// function OneClass { ... }
const obj2 = Reflect.construct(OneClass, args, OtherClass);
// Logs:
// OneClass
// function OtherClass { ... }
const obj3 = Object.create(OtherClass.prototype);
OneClass.apply(obj3, args);
// Output:
// OneClass
// undefined
```
## Specifications
{{Specifications}}
## Browser compatibility
{{Compat}}
## See also
- [Polyfill of `Reflect.construct` in `core-js`](https://github.com/zloirock/core-js#ecmascript-reflect)
- {{jsxref("Reflect")}}
- {{jsxref("Operators/new", "new")}}
- [`new.target`](/en-US/docs/Web/JavaScript/Reference/Operators/new.target)
- [`handler.construct()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/construct)