The behavior of new Object(value) - are implementations wrong?

Consider the behavior of "new Object(value)".

According to the spec ECMAScript® 2022 Language Specification, the Object constructor:

So, the call new Object(value) should create an empty ordinary object, right? There's no word here about arguments of the constructor. (And I'm not talking about function-style call Object(value)).

Although, in implementations, e.g. Chrome and Firefox, a call new Object('123') returns a bogus "String" object. So that e.g. new Object('123') === '1'.

Why is that? Why not an empty object? Or maybe I just misunderstand the spec? ;)

20.1.1.1 specifies the behavior of the function when called with one argument. Which will reach toObject(stringValue) for your example.

https://tc39.es/ecma262/#sec-object-value

An 'ordinary object' is an object that is not exotic. But new Object([1]) does return an Array, which is an exotic object.

This may be that constructors can always return a different object from the one they create. So the Object constructor may always create a ordinary object but it does not necessarily return that object.

class C {
  constructor() { return new String() }
}

new C;

The above call to the C constructor will create a new instance of C but a new String will be returned

Yes. And it does this. Keep in mind that ordinary objects consist of more than just basic Object objects. They're all objects that aren't exotic objects (as: "An exotic object is an object that is not an ordinary object").

This is handled in 2.1.1.1. The list in 2.1.1 is more of a summary. 2.1.1.1 refers to how Object behaves when called, both with and without new as determined by the presence of NewTarget:

When the Object function is called with optional argument value, the following steps are taken:

  1. If NewTarget is neither undefined nor the active function, then
    a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%").
  2. If value is undefined or null, return ! OrdinaryObjectCreate(%Object.prototype%).
  3. Return ! ToObject(value).

The first step accounts for when being used with super() which always creates a new Object object. The second step is when there is no value passed (or its passed but null or undefined). This always creates a new Object object. Finally, when value is passed, it runs it through ToObject - this both with and without using new. Ultimately there is no difference between:

Object('123') // String {"123"}
new Object('123') // String {"123"}

You can compare this to something like the Boolean constructor (20.3.1.1) where delineation between constructor and not is a little more clear with an explicit check for NewTarget being undefined.

When Boolean is called with argument value, the following steps are taken:

  1. Let b be ! ToBoolean(value).
  2. If NewTarget is undefined, return b.
  3. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%Boolean.prototype%", « [[BooleanData]] »).
  4. Set O.[[BooleanData]] to b.
  5. Return O.

Remember, the Object constructor doesn't check for "If NewTarget is undefined" which indicates no presence of new. It instead has a check for "If NewTarget is neither undefined nor the active function" for checking for super, which means everything else can still be a normal call or a new call.

Not sure what's going on here. This shouldn't be the case

new Object('123') === '1' // false

Hi,

In case the value passed as argument is a non-object, that phrase is correct, although it is not a complete description (the bogus String objects are indeed “ordinary objects”).

However, there is a contradiction between the phrase you have cited and the step 3 of the algorithm just below, in case the argument is itself an object; in that case no object is created. (And please, do not argue that such an object is created but not returned.)

Generally, the description text preceding the algorithm is informative, and the algorithm is normative, so that there is no bug in implementations (as they follow the algorithm), but there is a bug in the spec.

I’ve open Issue 2407 in order to track the spec bug.

1 Like

Agreed! I was wrong above, the spec text for the Object constructor definitely does not create a new object in all cases.

So, to summarize, new Object(value) is the same as Object(value)?

Or else what does it do?

Yes it looks like there is no observable difference between the two