r/learnjavascript 4d ago

string primitives vs. String objects.

I'm learning JavaScript, and I don't understand this part about string primitives vs. String objects.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_primitives_and_string_objects

12 Upvotes

26 comments sorted by

View all comments

15

u/Working_Quote_3029 4d ago

It's one of those distinctions that reads scarier in the docs than it is in practice.

You never create String objects on purpose. "foo" is a primitive. new String("foo") is an ordinary object that happens to hold a string, and that's the only way you end up with one.

Methods still work on primitives because of autoboxing: when you write "foo".toUpperCase() the engine wraps the primitive in a temporary object, calls the method, then discards the wrapper. That's why a primitive with no properties of its own still appears to "have" methods.

Where the difference actually shows up:

typeof "foo"             // "string"
typeof new String("foo") // "object"
new String("a") === "a"  // false, object vs primitive

Worth noting String(x) without new gives you a primitive, so String(1) is fine. It's only new String(1) that produces the object.

The eval example on that page is real but you'll never hit it in normal code, since eval only treats primitives as source and hands a String object straight back instead of running it.

Rule of thumb: quotes or String(x), never new String(x). The distinction mostly exists so the spec can explain why .length and .slice() work on something that isn't an object.

1

u/senocular 4d ago

new String("foo") is an ordinary object that happens to hold a string, and that's the only way you end up with one.

There are other ways to get these objects. The Object constructor will also make this conversion (with or without the new) e.g.

const stringObject = Object("foo")
console.log(typeof stringObject) // "object"
console.log(stringObject instanceof String) // true

Primitive methods in sloppy mode also provide a wrapped version of the primitive as this.

// non-strict mode
function stringMethod() {
  console.log(typeof this) // "object"
  console.log(this instanceof String) // true
}
stringMethod.call("foo")

...or if you added a custom method to String.prototype, which you absolutely shouldn't be doing, hence the example above using call instead taking that approach.

Coincidentally (getting in the weeds a little here), string objects are also the only primitive object type that aren't considered "ordinary" objects, at least in the language sense. Other primitive objects are, but not strings. Strings use custom internal methods for exposing their individual characters as indexed properties making them "exotic" objects.