JavaScript中字符串与数字的属性和方法来源疑问
Great question! This is one of those classic JavaScript quirks that confuses a lot of new developers—let me break it down simply.
First, you’re totally right: primitive data types (strings, numbers, booleans, null, undefined, symbols, BigInt) don’t have properties or methods of their own. So when you do something like 'hello'.toUpperCase() or 42.toString(), what’s actually happening under the hood?
JavaScript uses a trick called automatic wrapper objects. Here’s the step-by-step breakdown:
- When you try to access a property or call a method on a primitive value, JS temporarily wraps that primitive in its corresponding object type:
- Strings get wrapped in a
Stringobject - Numbers get wrapped in a
Numberobject - Booleans get wrapped in a
Booleanobject
- Strings get wrapped in a
- This wrapper object has all the built-in properties and methods you’re using (like
toUpperCase(),toString(),toFixed()). - Once the method/property access is done, JS immediately discards the wrapper object. The original primitive value stays unchanged (since primitives are immutable!).
Let’s take a concrete example to make this clear:
const greeting = 'hi there'; const shoutyGreeting = greeting.toUpperCase();
When we call greeting.toUpperCase(), JS secretly does this:
- Creates a temporary
Stringobject:new String('hi there') - Calls the
toUpperCase()method on this object, which returns'HI THERE' - Throws away the temporary
Stringobject - Assigns the result to
shoutyGreeting—the originalgreetingprimitive is still just'hi there'
You can even test this behavior if you try to add a custom property to a primitive:
let myStr = 'test'; myStr.customProp = 'something'; console.log(myStr.customProp); // Logs undefined!
Why? Because when you set myStr.customProp, you’re actually setting it on the temporary wrapper object that gets created for that line. As soon as that line finishes, the wrapper is gone. When you try to access myStr.customProp next, JS creates a brand new wrapper object—which doesn’t have the customProp you added earlier.
One last thing to note: you can manually create wrapper objects if you want (like new String('hello')), but this is almost never necessary. These wrapper objects are actual object types, not primitives, so they’ll behave differently in checks like typeof or strict equality (===).
Hope that clears up the confusion!
内容的提问来源于stack exchange,提问作者Kostya Hryshan

