// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. (function TestClass() { 'use strict'; var calls = 0; class Base { constructor(_) { assertEquals(Base, new.target); calls++; } } assertInstanceof(new Base(1), Base); assertInstanceof(new Base(1, 2), Base); assertInstanceof(new Base(), Base); assertEquals(3, calls); })(); (function TestDerivedClass() { 'use strict'; var calls = 0; class Base { constructor(expected) { assertEquals(expected, new.target); } } class Derived extends Base { constructor(expected) { super(expected); assertEquals(expected, new.target); calls++; } } new Derived(Derived, 'extra'); new Derived(Derived); assertEquals(2, calls); class Derived2 extends Derived {} calls = 0; new Derived2(Derived2); new Derived2(Derived2, 'extra'); assertEquals(2, calls); })(); (function TestFunctionCall() { var calls; function f(expected) { calls++; assertEquals(expected, new.target); } calls = 0; f(undefined); f(undefined, 'extra'); f(); assertEquals(3, calls); calls = 0; f.call({}, undefined); f.call({}, undefined, 'extra'); f.call({}); assertEquals(3, calls); calls = 0; f.apply({}, [undefined]); f.apply({}, [undefined, 'extra']); f.apply({}, []); assertEquals(3, calls); })(); (function TestFunctionConstruct() { var calls; function f(expected) { calls++; assertEquals(expected, new.target); } calls = 0; new f(f); new f(f, 'extra'); assertEquals(2, calls); })(); (function TestClassExtendsFunction() { 'use strict'; var calls = 0; function f(expected) { assertEquals(expected, new.target); } class Derived extends f { constructor(expected) { super(expected); assertEquals(expected, new.target); calls++; } } new Derived(Derived); new Derived(Derived, 'extra'); assertEquals(2, calls); })(); (function TestFunctionReturnObject() { function f(expected) { assertEquals(expected, new.target); return /abc/; } assertInstanceof(new f(f), RegExp); assertInstanceof(new f(f, 'extra'), RegExp); assertInstanceof(f(undefined), RegExp); assertInstanceof(f(), RegExp); assertInstanceof(f(undefined, 'extra'), RegExp); })(); (function TestClassReturnObject() { 'use strict'; class Base { constructor(expected) { assertEquals(expected, new.target); return /abc/; } } assertInstanceof(new Base(Base), RegExp); assertInstanceof(new Base(Base, 'extra'), RegExp); class Derived extends Base {} assertInstanceof(new Derived(Derived), RegExp); assertInstanceof(new Derived(Derived, 'extra'), RegExp); class Derived2 extends Base { constructor(expected) { super(expected); assertInstanceof(this, RegExp); } } assertInstanceof(new Derived2(Derived2), RegExp); assertInstanceof(new Derived2(Derived2, 'extra'), RegExp); })(); (function TestReflectConstruct() { var calls = 0; function f(expected) { calls++; assertEquals(expected, new.target); } var o = Reflect.construct(f, [f]); assertEquals(Object.getPrototypeOf(o), f.prototype); o = Reflect.construct(f, [f, 'extra']); assertEquals(Object.getPrototypeOf(o), f.prototype); assertEquals(2, calls); calls = 0; o = Reflect.construct(f, [f], f); assertEquals(Object.getPrototypeOf(o), f.prototype); o = Reflect.construct(f, [f, 'extra'], f); assertEquals(Object.getPrototypeOf(o), f.prototype); assertEquals(2, calls); function g() {} calls = 0; o = Reflect.construct(f, [g], g); assertEquals(Object.getPrototypeOf(o), g.prototype); o = Reflect.construct(f, [g, 'extra'], g); assertEquals(Object.getPrototypeOf(o), g.prototype); assertEquals(2, calls); })(); (function TestRestParametersFunction() { function f(...rest) { assertEquals(rest[0], new.target); } assertInstanceof(new f(f), f); assertInstanceof(new f(f, 'extra'), f); })(); (function TestRestParametersClass() { 'use strict'; class Base { constructor(...rest) { assertEquals(rest[0], new.target); } } assertInstanceof(new Base(Base), Base); assertInstanceof(new Base(Base, 'extra'), Base); class Derived extends Base {} assertInstanceof(new Derived(Derived), Derived); assertInstanceof(new Derived(Derived, 'extra'), Derived); })(); (function TestArrowFunction() { function f(expected) { (() => { assertEquals(expected, new.target); })(); } assertInstanceof(new f(f), f); assertInstanceof(new f(f, 'extra'), f); })(); (function TestRestParametersClass() { 'use strict'; class Base { constructor(expected) { (() => { assertEquals(expected, new.target); })(); } } assertInstanceof(new Base(Base), Base); assertInstanceof(new Base(Base, 'extra'), Base); class Derived extends Base {} assertInstanceof(new Derived(Derived), Derived); assertInstanceof(new Derived(Derived, 'extra'), Derived); })(); (function TestSloppyArguments() { var length, a0, a1, a2, nt; function f(x) { assertEquals(length, arguments.length); assertEquals(a0, arguments[0]); assertEquals(a1, arguments[1]); assertEquals(a2, arguments[2]); assertEquals(nt, new.target); if (length > 0) { x = 42; assertEquals(42, x); assertEquals(42, arguments[0]); arguments[0] = 33; assertEquals(33, x); assertEquals(33, arguments[0]); } } nt = f; length = 0; new f(); length = 1; a0 = 1; new f(1); length = 2; a0 = 1; a1 = 2; new f(1, 2); length = 3; a0 = 1; a1 = 2; a2 = 3; new f(1, 2, 3); nt = undefined; a0 = a1 = a2 = undefined; length = 0; f(); length = 1; a0 = 1; f(1); length = 2; a0 = 1; a1 = 2; f(1, 2); length = 3; a0 = 1; a1 = 2; a2 = 3; f(1, 2, 3); })(); (function TestStrictArguments() { var length, a0, a1, a2, nt; function f(x) { 'use strict'; assertEquals(length, arguments.length); assertEquals(a0, arguments[0]); assertEquals(a1, arguments[1]); assertEquals(a2, arguments[2]); assertEquals(nt, new.target); if (length > 0) { x = 42; assertEquals(a0, arguments[0]); arguments[0] = 33; assertEquals(33, arguments[0]); } } nt = f; length = 0; new f(); length = 1; a0 = 1; new f(1); length = 2; a0 = 1; a1 = 2; new f(1, 2); length = 3; a0 = 1; a1 = 2; a2 = 3; new f(1, 2, 3); nt = undefined; a0 = a1 = a2 = undefined; length = 0; f(); length = 1; a0 = 1; f(1); length = 2; a0 = 1; a1 = 2; f(1, 2); length = 3; a0 = 1; a1 = 2; a2 = 3; f(1, 2, 3); })(); (function TestOtherScopes() { function f1() { return eval("'use strict'; new.target") } assertSame(f1, new f1); function f2() { with ({}) return new.target } assertSame(f2, new f2); function f3({a}) { return new.target } assertSame(f3, new f3({})); function f4(...a) { return new.target } assertSame(f4, new f4); function f5() { 'use strict'; { let x; return new.target } } assertSame(f5, new f5); function f6() { with ({'new.target': 42}) return new.target } assertSame(f6, new f6); })(); // Has to be top-level to be inlined. function get_new_target() { return new.target; } (function TestInlining() { "use strict"; new function() { assertEquals(undefined, get_new_target()); } new function() { assertEquals(get_new_target, new get_new_target()); } class A extends get_new_target { constructor() { var new_target = super(); this.new_target = new_target; } } assertEquals(A, new A().new_target); })(); (function TestEarlyErrors() { assertThrows(function() { Function("new.target = 42"); }, ReferenceError); assertThrows(function() { Function("var foo = 1; new.target = foo = 42"); }, ReferenceError); assertThrows(function() { Function("var foo = 1; foo = new.target = 42"); }, ReferenceError); assertThrows(function() { Function("new.target--"); }, ReferenceError); assertThrows(function() { Function("--new.target"); }, ReferenceError); assertThrows(function() { Function("(new.target)++"); }, ReferenceError); assertThrows(function() { Function("++(new.target)"); }, ReferenceError); assertThrows(function() { Function("for (new.target of {});"); }, SyntaxError); })(); (function TestOperatorPrecedence() { function A() {} function constructNewTargetDotProp() { return new new.target.Prop } constructNewTargetDotProp.Prop = A; assertInstanceof(new constructNewTargetDotProp, A); function constructNewTargetBracketProp() { return new new.target['Prop'] } constructNewTargetBracketProp.Prop = A; assertInstanceof(new constructNewTargetBracketProp, A); function refNewTargetDotProp() { return new.target.Prop; } function B() {} refNewTargetDotProp.Prop = B; assertEquals(new refNewTargetDotProp, B); function refNewTargetBracketProp() { return new.target['Prop']; } refNewTargetBracketProp.Prop = B; assertEquals(new refNewTargetBracketProp, B); var calls = 0; function constructNewTargetArgsDotProp(safe) { this.Prop = ++calls; return safe ? Object(new new.target().Prop) : this; } assertInstanceof(new constructNewTargetArgsDotProp, constructNewTargetArgsDotProp); assertEquals(3, new constructNewTargetArgsDotProp(true) | 0); function constructNewTargetArgsBracketProp(safe) { this.Prop = ++calls; return safe ? Object(new new.target()['Prop']) : this; } assertInstanceof(new constructNewTargetArgsBracketProp, constructNewTargetArgsBracketProp); assertEquals(6, new constructNewTargetArgsBracketProp(true) | 0); function callNewTargetArgsDotProp(safe) { this.Prop = ++calls; return safe ? Object(new.target().Prop) : this; } assertInstanceof(new callNewTargetArgsDotProp(), callNewTargetArgsDotProp); assertEquals(new callNewTargetArgsDotProp(true) | 0, 9); function callNewTargetArgsBracketProp(safe) { this.Prop = ++calls; return safe ? Object(new.target()['Prop']) : this; } assertInstanceof(new callNewTargetArgsBracketProp(), callNewTargetArgsBracketProp); assertEquals(new callNewTargetArgsBracketProp(true) | 0, 12); function tagNewTarget(callSite, ...subs) { return callSite ? subs : new.target`${new.target.name}`; } assertEquals(new tagNewTarget, ["tagNewTarget"]); function C(callSite, ...subs) { return subs; } function tagNewTargetProp() { return new.target.Prop`${new.target.name}`; } tagNewTargetProp.Prop = C; assertEquals(new tagNewTargetProp, ["tagNewTargetProp"]); })();