Lesson guide
Learning objectives
- Explain the main purpose of Methods of primitives in JavaScript.
- Identify the syntax, APIs, or concepts introduced in this lesson.
- Use the examples to predict how JavaScript will behave before you run similar code.
- Connect this topic to nearby lessons in Data types.
Real-world context
This lesson matters when you need to recognize where Methods of primitives fits into real JavaScript programs. JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects.
Key ideas
- Methods of primitives is part of the Data types chapter, so it builds on the surrounding concepts rather than standing alone.
- Read each code example in two passes: first for the result, then for the rule that explains the result.
- When a section compares similar features, focus on the condition that makes you choose one feature over another.
Key terms
- Methods of primitives
- Methods
- primitives
- Data types
- JavaScript
JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects. They also provide methods to call as such. We will study those soon, but first we’ll see how it works because, of course, primitives are not objects (and here we will make it even clearer).
Let’s look at the key distinctions between primitives and objects.
A primitive
- Is a value of a primitive type.
- There are 7 primitive types:
string,number,bigint,boolean,symbol,nullandundefined.
An object
- Is capable of storing multiple values as properties.
- Can be created with
{}, for instance:{name: "John", age: 30}. There are other kinds of objects in JavaScript: functions, for example, are objects.
One of the best things about objects is that we can store a function as one of its properties.
let john = { name: "John", sayHi: function() { alert("Hi buddy!"); } }; john.sayHi(); // Hi buddy!
So here we’ve made an object john with the method sayHi.
Many built-in objects already exist, such as those that work with dates, errors, HTML elements, etc. They have different properties and methods.
But, these features come with a cost!
Objects are “heavier” than primitives. They require additional resources to support the internal machinery.
A primitive as an object
Here’s the paradox faced by the creator of JavaScript:
- There are many things one would want to do with a primitive, like a string or a number. It would be great to access them using methods.
- Primitives must be as fast and lightweight as possible.
The solution looks a little bit awkward, but here it is:
- Primitives are still primitive. A single value, as desired.
- The language allows access to methods and properties of strings, numbers, booleans and symbols.
- In order for that to work, a special “object wrapper” that provides the extra functionality is created, and then is destroyed.
The “object wrappers” are different for each primitive type and are called: String, Number, Boolean, Symbol and BigInt. Thus, they provide different sets of methods.
For instance, there exists a string method str.toUpperCase() that returns a capitalized str.
Here’s how it works:
let str = "Hello"; alert( str.toUpperCase() ); // HELLO
Simple, right? Here’s what actually happens in str.toUpperCase():
- The string
stris a primitive. So in the moment of accessing its property, a special object is created that knows the value of the string, and has useful methods, liketoUpperCase(). - That method runs and returns a new string (shown by
alert). - The special object is destroyed, leaving the primitive
stralone.
So primitives can provide methods, but they still remain lightweight.
The JavaScript engine highly optimizes this process. It may even skip the creation of the extra object at all. But it must still adhere to the specification and behave as if it creates one.
A number has methods of its own, for instance, toFixed(n) rounds the number to the given precision:
let n = 1.23456; alert( n.toFixed(2) ); // 1.23
We’ll see more specific methods in chapters Numbers and Strings.
Constructors String/Number/Boolean are for internal use only
Some languages like Java allow us to explicitly create “wrapper objects” for primitives using a syntax like new Number(1) or new Boolean(false).
In JavaScript, that’s also possible for historical reasons, but highly unrecommended. Things will go crazy in several places.
For instance:
alert( typeof 0 ); // "number" alert( typeof new Number(0) ); // "object"!
Objects are always truthy in if, so here the alert will show up:
let zero = new Number(0); if (zero) { // zero is true, because it's an object alert( "zero is truthy!?!" ); }
On the other hand, using the same functions String/Number/Boolean without new is totally fine and useful thing. They convert a value to the corresponding type: to a string, a number, or a boolean (primitive).
For example, this is entirely valid:
let num = Number("123"); // convert a string to number
null/undefined have no methods
The special primitives null and undefined are exceptions. They have no corresponding “wrapper objects” and provide no methods. In a sense, they are “the most primitive”.
An attempt to access a property of such value would give the error:
alert(null.test); // error
Common mistakes
- Skipping the small examples and then missing the exact rule that Methods of primitives depends on.
- Copying code without changing one value at a time to see which part controls the result.
- Treating similar-looking syntax or APIs as interchangeable before checking their edge cases.
Summary
- Primitives except
nullandundefinedprovide many helpful methods. We will study those in the upcoming chapters. - Formally, these methods work via temporary objects, but JavaScript engines are well tuned to optimize that internally, so they are not expensive to call.
Predict
Before running this check, predict all four lines. The first two use primitive methods, the third shows why wrapper objects are risky, and the fourth shows that null has no methods.
Reveal explanation
The output is HELLO, 1.23, true, and TypeError. A primitive string can call toUpperCase() because JavaScript temporarily provides a wrapper object, then returns a new primitive string. A primitive number can call toFixed(2), which returns the string "1.23". new Number(0) creates a real object, and objects are truthy even when they wrap zero. null and undefined have no wrapper methods, so accessing null.toString() throws a TypeError.
Try it
Replace new Number(0) with Number("0"), then predict the third line. This separates primitive conversion from explicitly creating a wrapper object.
Practice
- Rewrite one example from this lesson without looking at the original, then run it and compare the result.
- Change one input, operator, method call, or option in a code sample and predict what will happen before running it.
- Explain Methods of primitives in your own words as if you were reviewing it with another learner.
Keep learning
Continue with Numbers when you are ready for the next lesson.