Auto boxing
In JavaScript, there are different ways to create a string (or any other value for that matter).
const str1 = 'Imagine'; // literal form
const str2 = String('Imagine');
const strObj = new String('Imagine'); // constructor function form
We generally prefer the literal form 'Imagine'
when writing code, but how does it differ from other forms listed above? How can we invoke methods on this primitive value?
'Imagine'.length; // how are we able to access this property
'Imagine'.toUpperCase(); // or call any other String method
1971.toString(); // this works for other primitive types as well!
tl;dr
It works because of auto-boxing and a bit of coercion magic.
Primitives and objects
Considering the first example:
const str1 = 'Imagine';
const str2 = String('Imagine');
const strObj = new String('Imagine');
Both str1
and str2
hold a string
primitive value. strObj
on the other hand holds the (String
) object equivalent of string
.
The difference between str2
and strObj
initialization is the new
keyword. When the String
function is called without a new
keyword, it returns a primitive value. With a new
keyword it works as a constructor function and returns a String
object.
Therefore, str1
and str2
are identical (and both are a bit different from strObj
). Looking at their comparison:
const str1 = 'Imagine';
const str2 = String('Imagine');
console.log(str1 === str2); // true
const strObj = new String('Imagine');
console.log(str1 === strObj); // false
console.log(str1 == strObj); // true
A strict equality (===
) between the literal and object form returns false
but a coercive equality (==
) returns true
. This works since the object form “stores” the primitive value ('Imagine'
) and was able to coerce itself to the primitive form at the time of equality.
Note
We can also retrieve the primitive value (
string
) from a “wrapper” (String
) object using thevalueOf
method.
Boxing values
The above example explains the similarities between primitive and object values. Now, to uncover auto-boxing.
Here’s a recap, lets look at the types as well this time:
const str1 = 'Imagine';
const strObj = new String('Imagine');
console.log(typeof str1); // 'string'
console.log(typeof strObj); // 'object'
All methods and properties are available on the String
object’s prototype (length
, toUpperCase
, etc). When we call a method on a primitive type, JavaScript automatically converts (coerces or auto-boxes) the primitive value to its wrapper object, which has access to the methods. This lets us call methods directly on primitive values!
Now, whenever you take a look at this piece of code, you’ll be able to understand the magic and beauty behind it 🙂
// string primitive → String object → prototype → toUpperCase
'Imagine'.toUpperCase();
Personal blog of Divyanshu Maithani. I’m a software engineer working mostly on frontend. I also create programming videos with my friend. In my spare time I play music and DoTA.
You may follow me on twitter or join my newsletter for latest updates.