4

Definitive JavaScript by David Flanagan makes a distinction between Objects and Primitives.

He defines the primitives as Number, String, Boolean, Null, and Undefined, as does the standard.

However, would it be more accurate to define a primitive, as subset of object, i.e. to call them Primitive Objects.

Because they have their own methods and are complex entities.

Actual Question

Would Primitive Object be more accurate than Object when defining String, Boolean, and Number?

  • By the way, where were you *told everything in JavaScript was an object*? – kojiro Jan 18 '13 at 21:59
  • ...I think the person, meant compared to other languages, conceptually, there are more objects. –  Feb 01 '13 at 01:56

3 Answers3

3

Objects and primitives are distinct:

typeof 42 === "number"             
typeof new Number(42) === "object"
new Number(42) !== 42

However, when necessary, primitives are automatically wrapped by temporary objects, which can be automatically converted back into primitives:

(42).toString() === "42"
new Number(42) == 42
new Number(42) + 1 === 43

Especially in the context of the Java and C# programming languages, this sort of behavior is called autoboxing. As wrapper objects have some confusing characteristics, for example:

Boolean(new Boolean(false)) === true

it is good practice to avoid intentionally storing them in variables and instead use primitives whenever possible.

Community
  • 1
  • 1
PleaseStand
  • 31,641
  • 6
  • 68
  • 95
  • i see your point and i don't disagree...but it is untestable...you can't show that a primitive will break if you try and treat it like an object as it will "autobox" before you can. in its primitive state, you have to rely on the typeof operator to tell you this, but we don't know how typeof is implemented. –  Feb 01 '13 at 02:04
  • 1
    We also know `typeof` is wrong [in some cases](http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null). – kojiro Feb 01 '13 at 12:48
  • @kojiro: I considered mentioning the `typeof null` quirk; however, I decided to omit it as beside the point. – PleaseStand Feb 01 '13 at 15:16
  • @PleaseStand is it beside the point, though? I considered that `typeof` may be returning the *boxed* value of `null`. `typeof Object(null) === typeof null`. – kojiro Feb 01 '13 at 19:11
2

It's not about semantics, look:

var threePrimitive = 3;
var threeObject = new Number(3);

threePrimitive.toFixed(2); // 3.00
threeObject.toFixed(2); // 3.00

threePrimitive.foo = true
threeObject.foo = true;
threePrimitive.foo; // undefined
threeObject.foo; // true

Primitives are wrapped in objects when you try to call a method on them, but after initial use the object is thrown away.


As for how this is stated in the specification, I'm not 100% sure, but here is what I think (based on the tips left by Bergi in one of his answers. Section 11.2.1 states that the accessor properties should be evaluated as follows:

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be GetValue(baseReference).

(...)

Then in 8.7.1 we see the following:

The following [[Get]] internal method is used by GetValue when V is a property reference with a primitive base value. It is called using base as its this value and with property P as its argument. The following steps are taken:

  1. Let O be ToObject(base).
  2. Let desc be the result of calling the [[GetProperty]] internal method of O with property name P.
  3. If desc is undefined, return undefined.
  4. If IsDataDescriptor(desc) is true, return desc.[[Value]].
  5. Otherwise, IsAccessorDescriptor(desc) must be true so,
  6. let getter be desc.[[Get]]. If getter is undefined, return undefined.
  7. Return the result calling the [[Call]] internal method of getter providing base as the this value and providing no arguments.

NOTE The object that may be created in step 1 is not accessible outside of the above method. An implementation might choose to avoid the actual creation of the object. The only situation where such an actual property access that uses this internal method can have visible effect is when it invokes an accessor function.

Community
  • 1
  • 1
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • It's *entirely* a question about semantics. Your answer just happens to be *No, there is a difference between an Object Primitive and a Primitive*. – kojiro Jan 18 '13 at 21:08
  • Look at the last example: if you try to add a property to a primitive, you lose it! So we can't say it always behave like an object. – bfavaretto Jan 18 '13 at 21:16
  • Page 31 of ES5 (http://www.ecmascript.org/) - `―primitive‖ means Undefined, Null, Boolean, String, or Number.` –  Jan 18 '13 at 21:26
  • 1
    @bfavaretto Your comment makes it sound like you think I disagree, but I think we're talking about orthogonal subjects. I see your proof that `threePrimitive` and `threeObject` are different, but if the question was "Would *Primitive Object* [carry a] more accurate [meaning] then[sic] *Object*…?" then it's a *semantic* question, because it's about the meaning of words. – kojiro Jan 18 '13 at 21:26
  • @Hiro Those are the primitive *types* of the language, yes. `3` is a primitive *value* of the type `Number`. But it's not an object (not and `instanceof Object`). – bfavaretto Jan 18 '13 at 21:29
  • Distinction between primitive values and built in types - `A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, and String;` - page 2 –  Jan 18 '13 at 21:33
  • @kojiro You're right, I misinterpreted you when I added that reply. And you're right too about the semantics. The question is asking which would be the better term, but the fact is nothing will be 100% accurate unless we stick to the terms used in the language specification (which are rarely the most explanatory ones for those who are not used to the specs). – bfavaretto Jan 18 '13 at 21:34
  • and also interesting p31 - `―primitive‖ means Undefined, Null, Boolean, String, or Number.` –  Jan 18 '13 at 21:34
  • primitive types ( or objects have you ) hold primitive values - this is inline with spec. –  Jan 18 '13 at 21:44
  • @Hiro I'll try to add my understanding on how it works according to the specification. Kojiro was right from the start by stating this is a semantic discussion. And, as such, I'm not sure how constructive it is, since, as I said above, "nothing will be 100% accurate unless we stick to the terms used in the language specification". – bfavaretto Jan 18 '13 at 21:51
  • @Hiro I've seen your updates (btw, was the downvote from you?). The answer to your actual question is no, "primitive objects" is not more accurate. They're not objects, they're at a lower level (the lowest in the language). – bfavaretto Feb 01 '13 at 02:11
1

Would Primitive Object be more accurate then Object when defining String, Boolean, and Number?

Please note that I'm not saying that numbers are not objects here, I'm pointing out that it appears ambiguous. This is the kind of thing that confuses JavaScript newcomers.

The distinction is mostly academic, but there is one case where it seems ambiguous: literals represent primitive objects except when the literal appears to represent a number. You can't apply a method directly to a literal integer* symbol:

1.toString();
SyntaxError: identifier starts immediately after numeric literal

…but you can apply methods of Numbers:

Number(1).toString();
'1'

…and a name that contains a number is a Number:

x = 4;
x.toString();
'4'

I think this is actually a parsing problem, but I don't really know why the parser can't tell that 1 is a Number as easily as it can tell that "abc" is a String. I suppose it has to do with the semantic ambiguity of the . symbol. (Is it a decimal point or a method operator?)

*JavaScript doesn't actually have integers. I just mean a symbol that consists entirely of [0-9]+.

kojiro
  • 74,557
  • 19
  • 143
  • 201
  • So my supposition was right, then. Still, there's no compelling reason why the tokenizer couldn't figure this out. (Especially since ECMA doesn't allow method names to begin with a decimal number.) – kojiro Jan 18 '13 at 20:57
  • 1
    @Zeta: `1..toString()` :-P – gen_Eric Jan 18 '13 at 20:59
  • 1
    It's not academic, primitives are not objects! But they get wrapped when necessary. You can't do `1.toString()` for a different reason (the dot is interpreted as the decimal point), but you can use `1..toString()`. – bfavaretto Jan 18 '13 at 21:00
  • "note that I'm not saying that numbers are not objects here" -- I am. So I'm not one of those confirming your supposition. Neither I'm hitting you over the head (if you feel I am, I apologize, it was not my intention). – bfavaretto Jan 18 '13 at 21:07
  • Personally I think these comments are worth more than my answer, which @bfavaretto demonstrated is wrong. (Although I stand by the meta-analysis that this question is mostly academic and entirely a semantic one.) Thus I don't want to delete this answer or change it to destroy the context of the comments. So I've changed it to CW. – kojiro Jan 18 '13 at 21:13
  • From what I see, it is not just semantics as I originally guessed at (and if bfavaretto is correct ) then a primitive is distinct from an object. –  Feb 01 '13 at 02:09