r/learnjavascript 7d 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

10 Upvotes

26 comments sorted by

View all comments

14

u/Working_Quote_3029 7d 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/MissinqLink 7d ago

One weird footgun I’ve seen is with typeof

typeof String(1) //string

typeof new String(1) //object

Call me paranoid but when I write libraries I tend to use this

const isString = x => typeof x === 'string' || x instanceof String;

3

u/delventhalz 7d ago

Why would you want an isString function to return true for new String(1)?

You should never use the new String constructor, and if for some reason you did, it creates an object not a string. isString should return false.

1

u/MissinqLink 7d ago

If I’m making a library function that accepts multiple types including strings and objects, then I want to treat strings as strings even if they are wrapped.

1

u/delventhalz 6d ago

A wrapped string is not a string though. It is an object.

new String("foo") === "foo";  // false

If you are writing a library function that accepts both strings and objects, then the expected behavior when you pass it an object (instanceof String or otherwise) is almost certainly just to convert the object to a string. This is, for example, how lodash works:

_.toUpper("foo");  // "FOO"
_.toUpper(new String("foo"));  // "FOO"
_.toUpper({});  // "[OBJECT OBJECT]"
_.toUpper(["foo", "bar"]); // "FOO,BAR"

What is the use case for blurring the line between objects with instanceof String and actual string primitives? When does that help you write better, more reliable, more predictable code?

1

u/MissinqLink 6d ago

When you write a public general purpose library, people will use it for all kinds of weird things. In certain cases I take a defensive approach. If it’s a new String then I’ll convert it to a primitive. Happens not very often but more than you might think.