67

I've been messing around with the ECMA-262 standard (ECMAScript Language Specification, 3rd edition, if it matters for this - I have not found any difference between the 3rd and 5th edition on String Type / String Object).

There's one thing that baffles me: the difference between the String Type and the String Object. Yes I know the difference in the sense that the String Type is a sequence of 16-bit UTF-16 units and the String Object is a built-in object with its internal Class property set to "String" and its internal Value property set to a value of the String Type.

But reading the specification, the string type does not seem to expose any methods; that is, it's just a value without any additional properties. Take this code, everything is exactly as expected:

document.writeln(typeof "foo"); // 'string'
document.writeln(typeof new String("foo")); // 'object'

The first type is the actual String Type and the second is the Object Type (it's an object of class String, but its data type is object). However, looking at this:

"foo".charAt(0);

fooStrObj = new String("Foo");
fooStrObj.charAt(0);

They both seem to expose the same functions, but there are no functions on the String Type defined in the ECMA-262 standard; all the functions it exposes are from the String.prototype object (and I can see no reference to the fact that the String Type magically exposes all the properties and functions of the String.prototype object in the ECMA-262 standard). So are the values of type String Type automatically promoted to a String Object with the original String Type value as its internal Value property?

And if they are treated exactly the same (which for all intents and purposes they seem to be), why have two different ways to represent a String?

Chad
  • 1,750
  • 2
  • 16
  • 32
thr
  • 19,160
  • 23
  • 93
  • 130

2 Answers2

47

Strings are a value type in JS, so they can't have any properties attached to them, no prototype, etc. Any attempt to access a property on them is technically performing the JS [[ToObject]] conversion (in essence new String).

Easy way of distinguishing the difference is (in a browser)

a = "foo"
a.b = "bar"
alert("a.b = " + a.b); //Undefined

A = new String("foo");
A.b = "bar";
alert("A.b = " + A.b); // bar

Additionally while

"foo" == new String("foo")

is true, it is only true due to the implicit type conversions of the == operator

"foo" === new String("foo")

will fail.

olliej
  • 35,755
  • 9
  • 58
  • 55
  • Thank you, this is what I somewhat suspected, can you point me to where in the actual specification does it say this? – thr Jan 12 '10 at 19:56
  • 5
    See http://bclary.com/2004/11/07/#a-11.9.3 . If you mentally step through it, you'll end up at step 20 calling ToPrimitive on the String object; that ends up calling its `.toString()` method. – Jason Orendorff Jan 12 '10 at 19:59
  • thanks a lot mate! learned something new and you helped me a lot. :) +1 – Sagive Jan 27 '13 at 12:37
  • 1
    Distinction between string primitives and String objects: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Distinction_between_string_primitives_and_String_objects – Clarice Bouwer Dec 19 '13 at 11:57
  • One very important difference is that `new String("")` is truthy. – Knu Jan 12 '17 at 20:48
13

It's analogous to the difference between int and Integer in Java.

According to the standard, strings are automatically converted to String objects when you try to call a method. See ECMA 262-3 section 11.2.1; step 5 calls ToObject (which is defined in section 9.9).

11.2.1 Property Accessors
[...]
The production MemberExpression : MemberExpression [ Expression ] 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).


9.9 ToObject

The operator ToObject converts its argument to a value of type Object according to the following table:
[...]
Create a new String object whose [[value]] property is set to the value of the string. See 15.5 for a description of String objects.

As a specification technique, this is a hack to explain how strings can appear to have methods even though they're not really objects.

Apart from that, the wrapper objects are not very useful. I don't know why they're in the language. I rather wish they weren't. :)

try-catch-finally
  • 7,436
  • 6
  • 46
  • 67
Jason Orendorff
  • 42,793
  • 6
  • 62
  • 96
  • 1
    Ok, so basically javascript automatically boxes the string values to String objects during runtime when methods are called on them? If this is the case, why is it not defined in the specification (If it is and I have missed it, where can i find it?) ? – thr Jan 12 '10 at 19:51
  • It's not analogous to the difference between `int` and `Integer` in Java. `int` is a primitive type, and `Integer` is a class. While autoboxing usually removes the visible distinction in newer versions of Java, there is no primitive string type in Javascript. – friedo Jan 12 '10 at 19:53
  • friedo, strings are explicitly called primitive values in the standard. – Jason Orendorff Jan 12 '10 at 20:00
  • thr, It is defined in the specification. See the second paragraph of my answer. – Jason Orendorff Jan 12 '10 at 20:01
  • 1
    boxing might be a good analogy, although surely this distinction is optimized away somehow by the JavaScript engine so that it doesn't effect performance. – Triynko Aug 10 '13 at 09:33
  • 2
    The distinction may be optimized away in a few cases, but mostly String objects are bad for performance and you should avoid them. – Jason Orendorff Aug 10 '13 at 18:37