/* 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);