JavaScript has a handful of primitive types such as strings and numbers. However, when doing something fancy, it often wraps these types inside temporary objects in order to use object methods, a process apparently called auto-boxing.
This is equivalent to something like this:
a = 'hello';b = new String(a);console.log(b.toLowerCase());b = undefined; // ?To me it looks like a lot of overhead, especially since it has no intention of keeping the temporary object.
A language like Python, on the other hand, keeps all of its primitives in objects, so there’s no extra step.
Now I understand that memory and processing power wasn’t always as available in the past as it is now. That’s why, for example, Java (not -script) also kept primitives as non-objects. However Java didn’t handle these primitives the same way.
Is there a technical reason that JavaScript still does this? Is it more efficient, or is this behaviour just a legacy of more primitive times?
- $\begingroup$I believe the premise is no longer really true (even if it may have been the case back in the times of ECMA-262 1st Ed.). In strict-mode functions, the value of
thisis not autoboxed, and native built-ins are no longer evenspecified to autobox primitives (although this is ultimately an implementation detail anyway).$\endgroup$user3840170– user38401702025-11-27 13:20:57 +00:00Commented2 days ago - $\begingroup$"it has no intention of keeping the temporary object" - and that makes it rather trivial to optimise this away. Every engine worth its salt (and that includes old ones as well) does optimise (prototype) property lookups, and optimising property lookups on primitive values is hardly any extra effort. Notice that
a.toLowerCase()is in factb.toLowerCase.call(a)- the temporary object really isn't kept around for long.$\endgroup$Bergi– Bergi2025-11-27 21:50:46 +00:00Commentedyesterday - $\begingroup$Show me the autoboxing. I don't see it.$\endgroup$Joshua– Joshua2025-11-28 05:19:27 +00:00Commentedyesterday
- $\begingroup$@Joshua The "autoboxing" is that property dereference applied to values of non-object language types (lower-case number, string, boolean, bigint)is defined to be equivalent to creating the corresponding instance of the capital-letter Number, String, Boolean, or BigInt types and accessing the property on that; the code block is illustrating how that could be written out into language-level statements for the single expression
'hello'.toLowerCase()(ora.toLowerCase()foraholding astring-typed value).$\endgroup$2025-11-28 07:11:30 +00:00Commentedyesterday - $\begingroup$Ah; that makes a string a singularly unfortunate example for this.$\endgroup$Joshua– Joshua2025-11-28 14:26:37 +00:00Commentedyesterday
1 Answer1
A modern (high-performance) JavaScript engine is unlikely to allocate a heap object to run a single method, although the originals may well have done so. Depending on allocation and garbage collection strategies, that could be close to free anyway; if nothing else you can pre-allocate a single Number, String, and Boolean (and now BigInt) and swap the value inside of them out when you need to use it, since there's only ever one of these methods running at a time. The overhead doesn't need to be significant, and from the design perspective of letting the program keep running instead of crashing whenever possible it's a very JavaScript thing to do anyway.
A language like Python, on the other hand, keeps all of its primitives in objects, so there’s no extra step.
We could paraphrase this as "Python is slow all the time, instead of only sometimes" and it might highlight one issue that could motivate making different choices here. If you expect arithmetic operations to be much more common thantoFixed(), doing dynamic dispatch for them starts to sound like a pretty bad idea and occasionally allocating a short-lived object for rare operations sounds pretty good.
This is a caricature, and in practice you're not going to find much of significance between them; probably both avoid doing any of what the semantics would suggest in typical cases. In any case, Python is older than both Java and JavaScript, so it's not that putting everything in objects is a later invention (Smalltalk is from the 70s!).
However Java didn’t handle these primitives the same way.
I think it's worth noting here that Java absolutely does have autoboxing, and it's used every time a primitive value is stored in or retrieved from a list. It's probablymore of an overhead than JavaScript's in practice, since these genuinely do have to be real objects and they arise in potential hot loops. The term itself has been transferred from Java to JavaScript, which didn't have a name for this and doesn't call them boxed types.
The question is why do things this way: this is a language design question as much or more than a performance question. JavaScript arose under unusual conditions. In its public form it was meant to resemble Java. It was expected to be used primarily for very small things by people who weren't necessarily programmers before that. It was going to be encountered mostly by people who hadn't chosen to use it and didn't understand what it was, and visible breakage for them was undesirable.
At a lot of points it strives to let code carry on and maybe do the right thing rather than failing and breaking the web page. The "autoboxing" you're talking about isn't really identified as that specifically: it's "the program tried to use a member access on this non-object, so now theToObject coercion (§9.9) is applied to try to make that work", much like all the implicit coercions where"123" * 2 is246 or[[![]][+[]]+[]][+[]][+[]] is `"f". On this level, it's taking a program that would have crashed and salvaging it into something like what the programmer must have meant.
It is a choice to have the "boxed" types at all. These do hang a lot of utility functions off them, but it would have been possible to haveString.toLowerCase in the same way asMath.sin, or top-level functions like Python'sstr, and then purely have the primitive types. Actually storing the object forms of these types is quite rare. This would have looked less like Java, meant longer code where they were used, and been further from the Self-influenced OO design, but it's a viable road not taken.
Havingonly the object types does seem like it would have had performance implications at scale, if they did go through all the dispatch rigamarole and have to allocate a new heap object for x++, but it would be possible to present things that way at the surface and really use tagged pointers or something below that. This would have been practical at the time, and perhaps there's just historical contingency.
Whether or not it actually happens, autoboxing is a good story for how utility operations are made available: lettingx.toString() work all the time is good for programming with it, especially for the anticipated users who are not particularly programmers before that. Auto(un)boxing also means syntactic operators can be used for primitives and their equivalent lifted types, but don't need to be more generally exposed, which the object system wasn't terribly prepared for. There are some cases where you can distinguish them (typeof,new Number(1) != new Number(1)), but mostly it acts as though they are simultaneously both objects and primitives, depending on what you do.
The language also came about in ten days;mistakes were made.
- 1$\begingroup$"A modern (high-performance) JavaScript engine is unlikely to allocate a heap object to run a single method" the later specs also support this very explicitly. In v1 it just says that
ToObject(value)should be called. Howeverreading the property access spec now says thatGetValue(value)should be usedwhich itself has a note "An implementation might choose to avoid the actual creation of the object."$\endgroup$VLAZ– VLAZ2025-11-27 08:51:53 +00:00Commented2 days ago - 1
- 1$\begingroup$@Dada The allocation would have happened during the property access, not inside the method.$\endgroup$Bergi– Bergi2025-11-27 21:56:31 +00:00Commentedyesterday
- $\begingroup$The biggest mistake made in Javascript was switching from bytestrings to UTF-8 strings. Now we can't change the backing string type to UTF-8 for real performance gains and memory usage reduction.$\endgroup$Joshua– Joshua2025-11-28 14:29:58 +00:00Commentedyesterday
- 3$\begingroup$JavaScript doesn’t have either byte or UTF-8 strings and I don’t think the string representation has ever changed, other than perhaps the environmental change from UCS-2 to UTF-16 once that existed.$\endgroup$2025-11-28 17:14:07 +00:00Commented21 hours ago
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

