Write myNew(Constructor, ...args), which does what new Constructor(...args) does for a constructor function. Don't use new or Reflect.construct: call Constructor as a plain function, so inside it new.target is undefined. That's enough for ordinary constructor functions; classes, which refuse to run without new, are out of scope.
First, create an empty object whose prototype is Constructor.prototype. If Constructor.prototype isn't an object (someone set it to null or a number), use Object.prototype instead, as new does. Then call Constructor once, with that object as this and the arguments.
If the call returns an object or a function, return that. If it returns anything else (a primitive, null, or nothing at all), return the new object. Throw a TypeError if Constructor isn't a function.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return "Hi, " + this.name;
};
const ada = myNew(Person, "Ada");
ada.greet(); // "Hi, Ada"
ada instanceof Person; // true
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return "Hi, " + this.name;
};
const ada = myNew(Person, "Ada");
expect(Object.getPrototypeOf(ada)).toBe(Person.prototype);
expect(ada.greet()).toBe("Hi, Ada");
const Constructor = spy();
const made = myNew(Constructor, 1, 2);
expect(Constructor).toHaveBeenCalledTimes(1);
expect(Constructor).toHaveBeenCalledWith(1, 2);
expect(Constructor.calls[0].this).toBe(made);
function Counter() {
this.count = 0;
}
const a = myNew(Counter);
const b = myNew(Counter);
expect(a).not.toBe(b);
a.count++;
expect(b.count).toBe(0);
expect(Object.hasOwn(a, "count")).toBe(true);
expect(Object.hasOwn(Counter.prototype, "count")).toBe(false);
const custom = { custom: true };
function ReturnsObject() {
this.ignored = true;
return custom;
}
expect(myNew(ReturnsObject)).toBe(custom);
const helper = () => "helper";
function ReturnsFunction() {
return helper;
}
expect(myNew(ReturnsFunction)).toBe(helper);
function ReturnsNumber() {
this.a = 1;
return 42;
}
const fromNumber = myNew(ReturnsNumber);
expect(fromNumber).toBeInstanceOf(ReturnsNumber);
expect(fromNumber.a).toBe(1);
function ReturnsNull() {
this.b = 2;
return null;
}
const fromNull = myNew(ReturnsNull);
expect(fromNull).not.toBeNull();
expect(fromNull.b).toBe(2);
function Plain() {
this.ok = true;
}
Plain.prototype = null;
const first = myNew(Plain);
expect(Object.getPrototypeOf(first)).toBe(Object.prototype);
expect(first.ok).toBe(true);
Plain.prototype = 5;
expect(Object.getPrototypeOf(myNew(Plain))).toBe(Object.prototype);
expect(() => myNew({})).toThrow(TypeError);
expect(() => myNew("Person")).toThrow(TypeError);
let seen = "never called";
function Probe() {
seen = new.target;
}
myNew(Probe);
expect(seen).toBeUndefined();
Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.
Ctrl + Enter runs the tests (⌘ + Enter on a Mac).
I'm here to help with The new operator. I give hints, never the solution, so you get to solve it yourself. Ask for a hint, select code to ask about it, or press Ask Tuto why on a failing test.
Your first 3 answers need no account. for free to keep asking.