The new-able objects in JavaScript are:
- Functions created using the
function
keyword (excluding generator functions)
- Classes (which can be treated as functions)
- Bound function exotic objects ("bound functions")
- Some host objects
- Proxies if they are applied to one of the above
I know this because the only object types the new
operator works with are "constructors" (specification term). A constructor is an object with a [[Construct]]
internal method, and you can search the ECMAScript specification to find out which kinds of object have a [[Construct]]
internal method.
To make the result of a constructor function new-able, therefore, you must return one of the object kinds listed above.
Note that the specification specifically says that all constructors are definitionally functions because they must support the [[Call]]
internal method (note also the caveat below about host objects).
If you want to get very advanced, then you may be interested to learn that host objects do not appear to share the ordinary limitations for constructors (presumably for legacy Web compatibility reasons), but these are exceptional.
Explanation of the .constructor
property
When a new-able function f
is declared, two objects are created: the function-object f
itself, and a default object on the .prototype
own-property of f
. The .constructor
property of this default .prototype
object is automatically set by the runtime to be f
. I believe classes work in a very similar fashion. Note that the fact that the name of this property was chosen to be "prototype" makes discussing prototypes quite confusing in JavaScript (as it is distinct from the [[prototype]]
of the function).
This constructor
own-property on the object positioned on the .prototype
property, is never read by any built-in function or operation (that I know of). I view it as vestigial from the earliest days of JavaScript - it's original intent was as a way to maintain a link between the "class" that constructed an object as a developer affordance. Host environments (eg browsers) sometimes use it to infer the "type" of an object for the purposes of communicating with the user (eg. console output), the property is writeable and therefore unreliable.
Steps performed by the new
operator
At a high level, when new
is invoked against a constructor, the following steps occur (spec contains full details):
- A new object
o
is created
- The
[[Prototype]]
("the prototype") of o
is set to the value of the .prototype
property of the constructor (note this means the .constructor
property is inherited by the new object)
- The target (ie
this
) of the constructor body is set to o
- The constructor is run with the
this
value defined above
- If there is no explicit object-type return value, then
o
is returned by default