4

Trying to get my JavaSscript fundamentals strong. So the question is about string literals. Aren't they Objects? If your answer is 'yes' then my question is why is instanceof returning false?

> var s = new String
> s.constructor.toString()
function String() { [native code] }

> typeof s
object

> s instanceof String
true

> s instanceof Object
true

> s instanceof Number
false

So far so good.

> typeof 'c'
string

> 'c' instanceof Object
false

> 'c' instanceof String
false

> 'c'.length
1

> 'c'.charAt(0)
c

> 'c'.constructor.toString()
function String() { [native code] }
Chris
  • 44,602
  • 16
  • 137
  • 156
Murali
  • 1,495
  • 2
  • 15
  • 28
  • 3
    I'd say this question is a duplicate of http://stackoverflow.com/questions/203739/why-does-instanceof-return-false-for-some-literals too, but the answer on said duplicate is flat out wrong (outlined in comment to the accepted answer there). – Crescent Fresh Jan 07 '10 at 04:17
  • @Cresent Fresh - you are absolutely right! 3 .toString() or 3..toString() works (btw, what is going on with those two dots?) – Murali Jan 07 '10 at 04:35
  • When I tried with 3 dots, it get a strange error! 3...toString() TypeError on line 1: XML descendants internal method called on incompatible Number – Murali Jan 07 '10 at 04:35
  • 2
    @wizard@, First question: The *DecimalDigits* part of a *DecimalLiteral* part of a Number literal is optional (http://bclary.com/2004/11/07/#a-7.8.3), so the numeric literal ends with the first dot, the second dot is the property accessor. About the error: As you know now, `3.` is a complete Number literal, then the two other dots, are the `..` operator of ECMAScript for XML (also known as E4X) http://en.wikipedia.org/wiki/E4X – Christian C. Salvadó Jan 07 '10 at 05:25

2 Answers2

5

String literals are primitives (String values), String objects can be created with the String constructor in a new expression:

"foo" instanceof String // false

new String("foo") instanceof String // true

Edit: Something that seems to be confusing (by looking at the accepted answer here), is that you can still access properties defined on the prototype objects of primitive values, for example:

"foo".indexOf == String.prototype.indexOf // true
"foo".match == String.prototype.match // true
String.prototype.test = true;
"foo".test // true
true.toString == Boolean.prototype.toString
(3).toFixed == Number.prototype.toFixed // true
// etc...

The reason of that relies on the Property Accessors, the dot notation . and the bracket notation [].

Let's give a look to the algorithm in the ECMA-262 specification:

The production MemberExpression : MemberExpression [ Expression ] (or MemberExpression . Identifier) is evaluated as follows:

  1. Evaluate MemberExpression.

  2. Call GetValue(Result(1)).

  3. Evaluate Expression.

  4. Call GetValue(Result(3)).

  5. Call ToObject(Result(2)).

  6. Call ToString(Result(4)).

  7. Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).

In the Step 5, the ToObject internal operator type-converts the MemberExpression to object, depending on it's type.

The primitives are converted to Objects without noticing, and that's why you can access the properties defined on the prototype.

Community
  • 1
  • 1
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
0

Great explanation of this here. Copied for reference below.


That's because those things are primitives, and unless they need to be used as objects (when you are calling methods on them, for example) they remain so. The only time they "become" objects is when they need to be wrapped. If you are familiar with the concept of "boxing" in .NET, then think of it in that way.

Here is an example - take a look at this code:

Number.prototype.times = function(func) {
   for(var index = 1; index <= this; index++) {
      func(index);
   }
};

So, the following code will fail:

3.times(print); // assume 'print' writes to standard out

3, by itself is a primitive. That said, the following will work:

(3).times(print); // assume 'print' writes to standard out

That would display the numbers 1, 2, and 3. Because of the parenthesis, the JavaScript interpreter will temporarily wrap the primitive 3 in a Number object, call the method, and then garbage collect the object since it isn't needed any longer.

Anyway, a full discussion of this can be found in "JavaScript: The Definitive Guide."

Community
  • 1
  • 1
Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
  • Found it. 3.13. Primitive Datatype Wrapper Objects. Thanks again. – Murali Jan 07 '10 at 03:52
  • 4
    Er, no. `3.times` fails because it's a syntax error: the parser allows `3.` to be a decimal. The `()` simply removes the ambiguity, nothing to do with "boxing". Try it: `3 .times` works, as does `3..times`, as does `3. .times`. – Crescent Fresh Jan 07 '10 at 04:14
  • @Crescent, edited my answer to make this less confusing, about why you can access Number.prototype properties from a Number primitive as in this example – Christian C. Salvadó Jan 07 '10 at 05:28