A primitive is a single, simple value with no parts you can change: a string, number, bigint, boolean, undefined, null, or symbol. Primitives are the atoms of JavaScript. This lesson covers the rules that make them behave the way they do.
A primitive value can never be changed. You can only replace the variable's value with a new one:
let name = "ava";
name.toUpperCase(); // returns "AVA", but name is untouched
console.log(name); // "ava"
name[0] = "E"; // silently ignored
console.log(name); // "ava"
name = name.toUpperCase(); // REPLACE the value: now "AVA"
const is for. It means the value itself cannot be edited. let name can point to a new string any time; the old string never changes.
Two primitives are equal if they hold the same value, no matter where they came from:
const a = "Hel" + "lo";
const b = "Hello";
console.log(a === b); // true
console.log(0.5 + 0.5 === 1); // true
Assigning or passing a primitive always makes an independent copy:
function shout(msg) {
msg = msg.toUpperCase() + "!";
return msg;
}
const original = "hello";
const loud = shout(original);
console.log(original, loud); // "hello" "HELLO!"
If primitives are not objects, how can a string have a .length or a .toUpperCase() method? JavaScript briefly wraps the primitive in a temporary object, uses it, and throws it away. This is called auto-boxing:
"hi".length // 2 (temporary String wrapper)
(3.14159).toFixed(2) // "3.14" (temporary Number wrapper)
true.toString() // "true" (temporary Boolean wrapper)
Because the wrapper is thrown away, anything you try to store on a primitive disappears:
let word = "cat";
word.color = "orange"; // stored on a temporary wrapper...
console.log(word.color); // undefined ...which is already gone
"use strict", trying to set a property on a primitive throws a TypeError instead of silently doing nothing.
"hi".length works. What you cannot do is add or change properties, as the word.color example shows. In strict mode that line is TypeError: Cannot create property 'color' on string 'cat'.
new String(), new Number(), and new Boolean() create real wrapper objects, not primitives. They cause confusing bugs:
const s = new String("hi");
typeof s // "object" not "string"
s === "hi" // false
const f = new Boolean(false);
if (f) console.log("runs!") // runs: every object is truthy, even this one
Calling them without new is fine and useful: it converts a value to that primitive type.
String(42) // "42" primitive string
Number("7") // 7 primitive number
Boolean("") // false primitive boolean
Single or double quotes both work. A quote can appear inside a string as long as it is not the same kind that surrounds it:
const answer1 = "It's alright"; // single quote inside double quotes
const answer2 = 'He is called "Johnny"'; // double quotes inside single quotes
console.log(answer1);
console.log(answer2);
Many languages have separate types for whole numbers (like int) and decimals (like float or double). JavaScript has one: every number is a 64-bit decimal ("floating point") number. Very large or very small numbers can be written with e, meaning "times 10 to the power of":
console.log(34.00 === 34); // the same number: 34.00 is just 34
console.log(123e5); // 123 times 10 to the 5th
console.log(123e-5); // 123 times 10 to the -5th
Numbers lose accuracy above Number.MAX_SAFE_INTEGER (9007199254740991). A BigInt (added in 2020) holds whole numbers of any size. Make one with an n on the end, or from a string:
console.log(Number.MAX_SAFE_INTEGER + 2); // too big for a number: off by one
console.log(9007199254740993n);
console.log(BigInt("123456789012345678901234567890"));
Only true or false. You usually get them from comparisons:
let x = 5;
let y = 5;
let z = 6;
console.log(x == y, x == z);
let car;
console.log(car, typeof car);
car = "";
console.log(car === undefined, typeof car);
An empty string is a real value with a real type. It is not "no value."
null means "empty on purpose." typeof null is "object", a historical bug: null is a primitive. Check for it with ===:
const carName = null;
console.log(carName === null); // true only for null
console.log(carName == undefined); // == treats null and undefined as equal
console.log(undefined == null, undefined === null);
W3Schools says not to use == when checking for null. That is right when you mean only null. When you want "null or undefined," value == null is the one widely accepted use of == (see JS undefined).
const s = "text"; // string
const n = 42; // number
const big = 42n; // bigint
const ok = true; // boolean
let u; // undefined (declared, never assigned)
const nil = null; // null (deliberately empty)
const id = Symbol("id"); // symbol (unique; see Symbols)
What does this log?
let word = "cat";
word.toUpperCase();
word[0] = "b";
console.log(word);
cat. Strings are immutable: toUpperCase() returns a new string that is thrown away, and assigning to word[0] is silently ignored.Which one creates a primitive string?
new String("hi")String(42){ value: "hi" }["hi"]String() without new converts to a primitive, "42". A makes a wrapper object, and C and D are an object and an array.Why does console.log(9007199254740993) print 9007199254740992, and how do you store the exact value?
Number.MAX_SAFE_INTEGER, so a regular number cannot hold it exactly and rounds to the nearest value it can store. Use a BigInt: 9007199254740993n.word and confirm the original never changedtypeof "hi" with typeof new String("hi")new Boolean(false) passes an if check but Boolean(false) does not