4

When an object value is provided to the Object constructor, that value will be returned unchanged. So, given an object obj:

obj === new Object( obj )

and

obj === Object( obj )

Then, what's the point of doing Object( obj ) in the first place? I can understand doing Object( 'foo' ), or Object( 123 ) - it creates a wrapper object for the primitive value, but if we already have an object obj, why would we do Object( obj )?

Is this pattern useless?

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385

2 Answers2

4

The comparison will check whether obj is a real object. It is nearly equivalent to checking for

typeof obj == "object"

Yet, that is also true for null and can lead to strange errors when we try to access its properties. So, instead of writing if (typeof obj == "object" && obj !== null) it is commonly shortened to if (obj === Object(obj)).

Also, it yields true for function objects as well, while the typeof test does not - but sometimes you want to allow everything that can hold properties, and someone will get angry on your lib if you forget functions.

So much about the pattern, Reid has written an excellent answer about the internals of Object, which explains the behaviour you already described in your question.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • That's perfectly correct, but the assumption behind the question is that `obj` *be* an object (as per his comment on the question). There are definitely legitimate uses of the technique, but if you know (with ironclad certainty) that `obj` is an object, it is useless. – Reid May 14 '12 at 16:04
  • Yes, in that case the hole check is useless. But I missed other code snippets where the `Object` function was used, so I might have not understood the question. – Bergi May 14 '12 at 16:15
  • @Bergi That is a fine example, I didn't know about that. I must admit that I screwed up with the wording of my question. I actually meant all usages of the `Object` constructor, regardless of the input type. – Šime Vidas May 14 '12 at 16:39
  • "it is commonly shortened" - Well, I have *never* seen this before and quite honestly I think that the other variant is more readable, even if (or because!) it's more verbose. – user123444555621 May 14 '12 at 21:37
2

Assuming that obj is an Object value, it will have no effect. Let's look at the specification for ES5 (yay!).

According to § 15.2.1.1 Object([value]), if obj is not null or undefined, then we return ToObject(value).

Now we turn our attention to § 9.9 ToObject. It says that if the argument is of type Object, "the result is the input argument (no conversion)."

Hence, there is no theoretical reason to use Object(obj) where you know obj is an Object: it is the exact same as writing obj.

The other case you listed was new Object(obj), which depends on § 15.2.2.1 new Object([value]). It says that if value is supplied and the type of value is an Object, return obj if obj is a native ECMAScript object. If it is not native, then the result is implementation-defined (and therefore browser-dependent and not recommended to use, in my opinion).

Reid
  • 18,959
  • 5
  • 37
  • 37
  • Usually, when the question is about the usefulness of a certain feature, then it is expected that the answers provide usages of that feature, and therefore affirm its usefulness. Answers like "It's not useful" are not useful, because they rely on the experience of the answerer. There might exist usages that you don't know of... – Šime Vidas May 14 '12 at 16:15
  • 1
    @ŠimeVidas: Your comment on the question said "Assuming that `obj` is an Object value, ...". If you assume that `obj` is an Object value, then it *is* useless: the spec *proves* so. Unless one of the browsers has a broken implementation of the spec (which has certainly happened before, I concede: array literals with elided elements come to mind), there is no other possible answer given your constraints. – Reid May 14 '12 at 16:17
  • Just because it returns the input unchanged, does not mean that it's useless. – Šime Vidas May 14 '12 at 16:19
  • But it does. The two are algebraically equivalent. Assuming that `obj` is an object, `Object(obj)` is *identical* to just writing `obj`. And because `obj === obj` is true for all objects, you might as well just replace `obj === Object(obj)` with the `true`. So I suppose you could use the above statement as an alias for the boolean true. – Reid May 14 '12 at 16:22
  • What I meant is that the `Object` constructor behaves like an identity function for objects. I think that there are certainly usages for an identity function in JavaScript (or any language). This is only one example of a legitimate usage (I think), and there might be other usages as well. – Šime Vidas May 14 '12 at 16:26
  • I have found one usage - converting NodeList object to true arrays: `var arr = [].map.call( nodeList, Object );` – Šime Vidas May 14 '12 at 17:20
  • @ŠimeVidas: Yes, I thought about that as soon as you said "identity function". But I don't think it will make a good use case, because it is equivalent to the slice function... – Bergi May 14 '12 at 22:44
  • @Bergi Slice doesn't work in IE8/7 on node lists. This - `var arr = [].slice.call( nodeList, 0 );` - throws an error. That is why we need a different method and the code I posted above is the best solution I know of. – Šime Vidas May 14 '12 at 23:11
  • @ŠimeVidas: OK, but they also don't implement Array.prototype.map, do they? – Bergi May 14 '12 at 23:17
  • @Bergi No, but it's trivial to provide ES5-shim. – Šime Vidas May 14 '12 at 23:23