# Standard constructors and the new operator

**URL:** <https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924>\
**Category:** I have questions\
**Created:** [February 13, 2024, 1:15pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924 "2024-02-13T13:15:05Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![MaineGardener](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mainegardener/32/2012_2.png) [@MaineGardener](https://es.discourse.group/u/MaineGardener)\
**Post date:** [February 13, 2024, 1:15pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/1 "2024-02-13T13:15:05Z")

</div>

Why do various standard constructors behave differently when invoked with and without the `new` operator. I've identified four categories:

1. Different. These constructors return an object when invoked with `new` and a primitive value otherwise. They are `Boolean`, `Date`, `Number`, `RegExp`, and `String`.

2. Same. These constructors return an object when invoked with or without the `new` operator. Examples include `Array`, `Error`, `Function`, `Object`, and the aggregate and native errors.

3. Only new. These constructors return an object when invoked with `new` and throw `TypeError` otherwise. Examples include `ArrayBuffer`, the `TypedArray` constructors, `DataView`, `Map`, `Promise`, etc.

4. No new. These constructors throw a `TypeError` when invoked with `new` and return a primitive value otherwise. They are `BigInt` and `Symbol`.

I am writing a Medium article about this, and I would be glad for perspectives from the community.  
I am guessing there are both functional and historical reasons. Thank you for your thoughts!

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [February 13, 2024, 2:35pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/2 "2024-02-13T14:35:20Z")

</div>

> [@MaineGardener](#):
>
> Different. These constructors return an object when invoked with `new` and a primitive value otherwise. They are `Boolean`, `Date`, `Number`, `RegExp`, and `String`.

The "primitive value otherwise" doesn't apply to RegExp here. RegExp returns RegExp objects in both cases (the difference between being called as a constructor and a function is that the function version may return the argument its given rather than a new RegExp if that argument is itself already a RegExp).

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [February 13, 2024, 6:30pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/3 "2024-02-13T18:30:04Z")

</div>

Category 1 is for pre-ES6 non-nullish primitives. Category 2 is pre-ES6 builtin objects. Category 3 is post-ES6 builtin objects. Category 4 is post-ES6 primitives.

(Date is a weird legacy constructor from pre-ES6 which, when invoked without `new`, returns a string)

The "why" is just because ideas driving the language, along with the people involved, shift over time.

---

<div class="post-metadata">

**Author:** ![MaineGardener](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mainegardener/32/2012_2.png) [@MaineGardener](https://es.discourse.group/u/MaineGardener)\
**Post date:** [February 13, 2024, 8:28pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/4 "2024-02-13T20:28:15Z")

</div>

Thanks, senocular and ljharb. Regarding `Date`, I'm looking forward to `Temporal`. Regarding Category 1, I'm still curious why `new Boolean` seemed like a good idea at the time, but that's just with the advantage of hindsight. Appreciate the input, and I'll leave this topic open in case anyone else is willing to provide some historical context.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [February 13, 2024, 10:08pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/5 "2024-02-13T22:08:48Z")

</div>

If you're not already familiar with [JavaScript the first 20 years](https://dl.acm.org/doi/10.1145/3386327), that could be a source for some information as it covers a lot around some of the early development of the language. The old [https://esdiscuss.org/](https://esdiscuss.org/) list could also be useful as well. And of course there's always the [proposals](https://github.com/tc39/proposals) covering everything post-ES6 (e.g. looking into [BigInt issues](https://github.com/tc39/proposal-bigint/issues?q=is%3Aissue) could possibly shed some extra light there).

---

<div class="post-metadata">

**Author:** ![MaineGardener](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/mainegardener/32/2012_2.png) [@MaineGardener](https://es.discourse.group/u/MaineGardener)\
**Post date:** [February 13, 2024, 10:24pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/6 "2024-02-13T22:24:49Z")

</div>

Thank you, senocular. I didn't know about [JavaScript the first 20 years](https://dl.acm.org/doi/10.1145/3386327). I'll read it. Looks like the source I'm looking for.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 1:08pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/7 "2024-02-22T13:08:01Z")

</div>

Maybe worth considering the `Object(thing)` case which makes both `Symbol` and `BigInt`, together with other primitives, an actual object, instance of their primitive constructor.

The most notable shenanigan there is `Object(null)` which doesn't return the equivalent of `Object.create(null)`, it returns an object literal.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [February 22, 2024, 2:27pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/8 "2024-02-22T14:27:01Z")

</div>

Why would you expect `Object` to behave the same as `Object.create`?

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 3:31pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/9 "2024-02-22T15:31:58Z")

</div>

> [@bergus](#):
>
> Why would you expect `Object` to behave the same as `Object.create`?

I wouldn't expect that for anything but `Object('string')` return a `new String('string')` and `Object(false)` return a `new Boolean(false)` **but** `Object(null)` return just `{}` instead of an object which primitive/prototype is actually `null` ... all others can be reverse-engineered to their primitive form/shape/type, `Object(null)` cannot.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [February 22, 2024, 3:45pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/10 "2024-02-22T15:45:27Z")

</div>

It is indeed a legacy inconsistency that Object doesn’t throw on nullish values; it should.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 3:53pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/11 "2024-02-22T15:53:49Z")

</div>

I wouldn't say _nullish_ ... `Object(undefined)` throwing? I am OK with it, but `Object(null)` as (faster?) shortcut for `Object.create(null)` ... I'd sign for it instead of having just a literal ... I guess it's too late for that though, I wasn't suggesting a change, rather underlying that legacy quirk that couldn't be fixed in ES 5.1 time.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 3:58pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/12 "2024-02-22T15:58:17Z")

</div>

to expand:

```js
Object(false).valueOf() === false; // true
Object('').valueOf() === ''; // true
Object(Symbol.for('symbol')).valueOf() === Symbol.for('symbol'); // true

Object(null).valueOf() === null; // false

```

That's it ... anything can be used as primitive even behind an `Object(...)` call, but not `null` ... this is again not a request, just yet another quirk in legacy JS.

**edit** ironically enough `Object(null).valueOf()` should also throw as `null` prototype has no such method 😅

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [February 22, 2024, 4:11pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/13 "2024-02-22T16:11:14Z")

</div>

That simply wouldn’t make any sense; Object doesn’t take a [[Prototype]] value.

The thing that it does with all non-nullish values is make an object form of it; since null and undefined aren’t object-coercible, it can’t make an object form of it, so it should throw.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 4:17pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/14 "2024-02-22T16:17:19Z")

</div>

> [@ljharb](#):
>
> Object doesn’t take a [[Prototype]] value.

I guess it's PoV and DX ... `Object('')` generates an `instanceof String` out of the type of the argument so it infers the prototype and return `new String('')` ... the same could be done for `Object(null)` where the the inferred prototye is the same behind `Object.prototype` itself and return what `Object.create(null)` does.

To me that would've worked wonderfully, instead I need to know `Object(null)` doesn't do what I expect and fallback to `Object.create(null)` when `Object(null)` is actually what I meant 🤷

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [February 22, 2024, 6:12pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/15 "2024-02-22T18:12:54Z")

</div>

> [@WebReflection](#):
>
> an object which primitive/prototype is actually `null`

I'm not sure why you're throwing these into the same box. The internal _[[Prototype]]_ of an object and the internal _[[PrimitiveValue]]_ of an object are two completely separate concepts. An object which is not a `Boolean`/`String`/`Number`/`Symbol`/`BigInt` instance simply doesn't have a _[[PrimitiveValue]]_, no matter whether it is `Obect.create(null)` or `Object.create(Object.prototype)`/`{}`.

It seems like you want `Object(x).valueOf() === x` to hold for all `x`, but that wouldn't even work if `Object(null)` returned `Object.create(null)`/`{ __proto__ : null}`.

---

<div class="post-metadata">

**Author:** ![WebReflection](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/webreflection/32/248_2.png) [@WebReflection](https://es.discourse.group/u/WebReflection)\
**Post date:** [February 22, 2024, 8:43pm UTC](https://es.discourse.group/t/standard-constructors-and-the-new-operator/1924/16 "2024-02-22T20:43:51Z")

</div>

I don’t think this conversation is worth anyone time and I don’t personally care about it neither … simply put: the DX on Object(null) is both misleading and considered a legacy mistake while I would love for it to have been a faster shortcut to Object.create(null).

That’s it, that’s my comment and if anyone is going to write a post about constructors and object primitive wrappers via Object(type) I think it’s worth mentioning null case too, as that means nothing and it’s a pity (to me).

The rest is history, I was never here to change that, I was here to suggest the Object(bigint) and others where new BigInt or Symbol would fail, yet there are wrappers for those too.
