blob: 7dbb9bfa7dfd74f3a78e0a737c184b0866eaadf8 [file] [log] [blame]
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Reflect.construct invokes constructors.
assertDeepEq(Reflect.construct(Object, []), {});
assertDeepEq(Reflect.construct(String, ["hello"]), new String("hello"));
// Constructing Date creates a real Date object.
var d = Reflect.construct(Date, [1776, 6, 4]);
assertEq(d instanceof Date, true);
assertEq(d.getFullYear(), 1776); // non-generic method requires real Date object
// [[Construct]] methods don't necessarily create new objects.
var obj = {};
assertEq(Reflect.construct(Object, [obj]), obj);
// === Various kinds of constructors
// We've already seen some builtin constructors.
//
// JS functions:
function f(x) { this.x = x; }
assertDeepEq(Reflect.construct(f, [3]), new f(3));
f.prototype = Array.prototype;
assertDeepEq(Reflect.construct(f, [3]), new f(3));
// Bound functions:
var bound = f.bind(null, "carrot");
assertDeepEq(Reflect.construct(bound, []), new bound);
// Classes:
class Base {
constructor(...args) {
this.args = args;
this.newTarget = new.target;
}
}
class Derived extends Base {
constructor(...args) { super(...args); }
}
assertDeepEq(Reflect.construct(Base, []), new Base);
assertDeepEq(Reflect.construct(Derived, [7]), new Derived(7));
g = Derived.bind(null, "q");
assertDeepEq(Reflect.construct(g, [8, 9]), new g(8, 9));
// Cross-compartment wrappers:
var g = newGlobal();
var local = {here: this};
g.eval("function F(arg) { this.arg = arg }");
assertDeepEq(Reflect.construct(g.F, [local]), new g.F(local));
// If first argument to Reflect.construct isn't a constructor, it throws a
// TypeError.
var nonConstructors = [
{},
Reflect.construct, // builtin functions aren't constructors
x => x + 1,
Math.max.bind(null, 0), // bound non-constructors aren't constructors
((x, y) => x > y).bind(null, 0),
// A Proxy to a non-constructor function isn't a constructor, even if a
// construct handler is present.
new Proxy(Reflect.construct, {construct(){}}),
];
for (var obj of nonConstructors) {
assertThrowsInstanceOf(() => Reflect.construct(obj, []), TypeError);
assertThrowsInstanceOf(() => Reflect.construct(obj, [], Object), TypeError);
}
// === new.target tests
// If the newTarget argument to Reflect.construct is missing, the target is used.
function checkNewTarget() {
assertEq(new.target, expected);
expected = undefined;
}
var expected = checkNewTarget;
Reflect.construct(checkNewTarget, []);
// The newTarget argument is correctly passed to the constructor.
var constructors = [Object, Function, f, bound];
for (var ctor of constructors) {
expected = ctor;
Reflect.construct(checkNewTarget, [], ctor);
assertEq(expected, undefined);
}
// The newTarget argument must be a constructor.
for (var v of SOME_PRIMITIVE_VALUES.concat(nonConstructors)) {
assertThrowsInstanceOf(() => Reflect.construct(checkNewTarget, [], v), TypeError);
}
// The builtin Array constructor uses new.target.prototype and always
// creates a real array object.
function someConstructor() {}
var result = Reflect.construct(Array, [], someConstructor);
assertEq(Reflect.getPrototypeOf(result), someConstructor.prototype);
assertEq(result.length, 0);
assertEq(Array.isArray(result), true);
// For more Reflect.construct tests, see target.js and argumentsList.js.
reportCompare(0, 0);