DEV Community

Glad Chinda
Glad Chinda

Posted on

Wrap everything that can be wrapped

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:

  1. Primitivesstrings, numbers, booleans, symbols, null, undefined
  2. Objectsanything 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 LiteralProduces 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() FunctionProduces a String object when called as a constructor with the new keyword, and casts its argument to a string primitive when called without the new 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.

ECMAScript GetV() abstract operation

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)