Hello there,
Do you have 3-5 minutes to spare? If so, let's have a brief discussion about Wrapper Objects in JavaScript.
Background
Data types in JavaScript can be grouped into two broad categories:
-
Primitives — strings, numbers, booleans, symbols,
null
,undefined
- Objects — anything that's not a primitive (arrays, functions, etc)
While primitives are usually simple immutable values, objects, on the other hand, are collections of one or more properties (each property having a name, and a value that can be of any data type).
Let's consider strings for a moment
Strings in JavaScript can be created in two ways:
- String Literal — Produces a string primitive.
// String literal
const string1 = 'Hello';
const string2 = 'Hello';
console.log(string1[0]); // "H"
console.log(string2.length); // 5
console.log(typeof string1); // "string"
console.log(string1 === string2); // true
-
String()
Function — Produces aString
object when called as a constructor with thenew
keyword, and casts its argument to a string primitive when called without thenew
keyword.
// String Constructor
const string1 = new String('Hello');
const string2 = new String('Hello');
console.log(string1[0]); // "H"
console.log(string2.length); // 5
console.log(typeof string1); // "object"
console.log(string1 === string2); // false
Since a string primitive (created with the string literal syntax) is not an object (as shown in the code snippets above), how is it that we are able to access properties like length
on it as though it is a String
object?
The reason is because at the time we are accessing the said property (length
), we are already dealing with a String
object (wrapper object).
Wrapper Objects
The ECMAScript language specification defines an abstract operation for accessing the value of a property from a value. If the value is not an object (e.g string primitive), then the property lookup is performed on a wrapper object appropriate for the type of the value.
Hence, whenever we try to access a property from the string literal, the JavaScript engine does the following:
- Create a one-off
String
wrapper object for the string literal - Access the specified property on the wrapper object
- Discard the
String
wrapper object.
// String primitive
const greeting = 'Hello World';
// Access and call toUpperCase() method
// Equivalent to: (new String(greeting)).toUpperCase()
console.log(greeting.toUpperCase()); // "HELLO WORLD"
The above behavior also applies to other primitive values like numbers, booleans and symbols. However, trying to access a property on null
and undefined
will throw a TypeError, since a wrapper object cannot be created for them.
// Number primitive
const price = 12.357;
// Null primitive
const nullValue = null;
// Access and call `Number` methods
// Equivalent to: (new Number(price)).toFixed(2)
console.log(number.toFixed(2)); // 12.36
// Equivalent to: (new Number(price)).toExponential(2)
console.log(number.toExponential(2)); // 1.24e+1
// Access a property on a Null primitive
// Throws TypeError
console.log(null.length);
In summary, the JavaScript engine knows how to wrap everything that can be wrapped, whenever it is required to do so.
❤️ Like and Share
If you found this post insightful in any way please:
- Like this post
- Comment your feedback
- Share with someone
- Follow me on Twitter
Top comments (0)