Chapter 1Values, Types, and Operators
Below the surface of the machine, the program moves. Without effort, it expands and contracts. In great harmony, electrons scatter and regroup. The forms on the monitor are but ripples on the water. The essence stays invisibly below.
Inside the computer’s world, there is only data. You can read data, modify data, create new data—but anything that isn’t data simply does not exist. All this data is stored as long sequences of bits and is thus fundamentally alike.
Bits are any kind of two-valued things, usually described as zeroes and ones. Inside the computer, they take forms such as a high or low electrical charge, a strong or weak signal, or a shiny or dull spot on the surface of a CD. Any piece of discrete information can be reduced to a sequence of zeros and ones and thus represented in bits.
For example, think about how you might show the number 13 in bits. It works the same way you write decimal numbers, but instead of 10 different digits, you have only 2, and the weight of each increases by a factor of 2 from right to left. Here are the bits that make up the number 13, with the weights of the digits shown after them:
0 0 0 0 1 1 0 1 128 64 32 16 8 4 2 1
So that’s the binary number 00001101, or 8 + 4 + 1, which equals 13.
Imagine a sea of bits. An ocean of them. A typical modern computer has more than 30 billion bits in its volatile data storage. Nonvolatile storage (the hard disk or equivalent) tends to have yet a few orders of magnitude more.
To create a value, you must merely invoke its name. This is convenient. You don’t have to gather building material for your values or pay for them. You just call for one, and woosh, you have it. They are not created from thin air, of course. Every value has to be stored somewhere, and if you want to use a gigantic amount of them at the same time, you might run out of bits. Fortunately, this is a problem only if you need them all simultaneously. As soon as you no longer use a value, it will dissipate, leaving behind its bits to be recycled as building material for the next generation of values.
Use that in a program, and it will cause the bit pattern for the number 13 to come into existence inside the computer’s memory.
Computer memory used to be a lot smaller, and people tended to use groups of 8 or 16 bits to represent their numbers. It was easy to accidentally overflow such small numbers—to end up with a number that did not fit into the given amount of bits. Today, even personal computers have plenty of memory, so you are free to use 64-bit chunks, which means you need to worry about overflow only when dealing with truly astronomical numbers.
Fractional numbers are written by using a dot.
For very big or very small numbers, you can also use scientific notation by adding an “e” (for “exponent”), followed by the exponent of the number:
That is 2.998 × 108 = 299800000.
Calculations with whole numbers (also called integers) smaller than the aforementioned 9 quadrillion are guaranteed to always be precise. Unfortunately, calculations with fractional numbers are generally not. Just as π (pi) cannot be precisely expressed by a finite number of decimal digits, many numbers lose some precision when only 64 bits are available to store them. This is a shame, but it causes practical problems only in specific situations. The important thing is to be aware of it and treat fractional digital numbers as approximations, not as precise values.
100 + 4 * 11
symbols are called operators. The first stands for addition, and the
second stands for multiplication. Putting an operator between two
values will apply it to those values and produce a new value.
Does the example mean “add 4 and 100, and multiply the result by 11”, or is the multiplication done before the adding? As you might have guessed, the multiplication happens first. But, as in mathematics, you can change this by wrapping the addition in parentheses.
(100 + 4) * 11
For subtraction, there is the
and division can be done with the
When operators appear together without parentheses, the order in which
they are applied is determined by the precedence of the
operators. The example shows that multiplication comes before
/ operator has the same precedence as
-. When multiple operators with the same precedence
appear next to each other (as in
1 - 2 + 1), they are applied left
to right (
(1 - 2) + 1).
These rules of precedence are not something you should worry about. When in doubt, just add parentheses.
There is one more arithmetic operator, which you might not
immediately recognize. The
% symbol is used to represent the
X % Y is the remainder of dividing
Y. For example,
314 % 100 produces
144 % 12 gives
Remainder’s precedence is the same as that of multiplication and
division. You’ll often see this operator referred to as modulo,
though technically remainder is more accurate.
The first two are
represent the positive and negative infinities.
Infinity - 1 is
Infinity, and so on. Don’t put too much trust in
infinity-based computation. It isn’t mathematically solid, and it will
quickly lead to our next special number:
NaN stands for “not
a number”, even though it is a value of the number type. You’ll get
this result when you, for example, try to calculate
0 / 0 (zero
divided by zero),
Infinity - Infinity, or any number of other
numeric operations that don’t yield a precise, meaningful result.
The next basic data type is the string. Strings are used to represent text. They are written by enclosing their content in quotes.
"Patch my boat with chewing gum" 'Monkeys wave goodbye'
Both single and double quotes can be used to mark strings as long as the quotes at the start and the end of the string match.
To be able to have such characters in a string, the following notation is used: whenever a backslash (“\”) is found inside quoted text, it indicates that the character after it has a special meaning. This is called escaping the character. A quote that is preceded by a backslash will not end the string but be part of it. When an “n” character occurs after a backslash, it is interpreted as a newline. Similarly, a “t” after a backslash means a tab character. Take the following string:
"This is the first line\nAnd this is the second"
The actual text contained is this:
This is the first line And this is the second
There are, of course, situations where you want a backslash in a
string to be just a backslash, not a special code. If two backslashes
follow each other, they will collapse together, and only one will be
left in the resulting string value. This is how the string “
character is written like "\n".” can be expressed:
"A newline character is written like \"\\n\"."
Strings cannot be divided,
multiplied, or subtracted, but the
+ operator can be used on them.
It does not add, but it concatenates—it glues two strings together.
The following line will produce the string
"con" + "cat" + "e" + "nate"
There are more ways of manipulating strings, which we will discuss when we get to methods in Chapter 4.
Not all operators are
symbols. Some are written as words. One example is the
operator, which produces a string value naming the type of the value
you give it.
console.log(typeof 4.5) // → number console.log(typeof "x") // → string
We will use
console.log in example code to indicate that we want to see the
result of evaluating something. When you run such code, the value
produced should be shown on the screen, though how it appears will
The other operators we saw all operated on two values, but
typeof takes only one. Operators that use two values are called
binary operators, while those that take one are called unary
operators. The minus operator can be used both as a binary operator
and as a unary operator.
console.log(- (10 - 2)) // → -8
Here is one way to produce Boolean values:
console.log(3 > 2) // → true console.log(3 < 2) // → false
< signs are the traditional
symbols for “is greater than” and “is less than”, respectively. They
are binary operators. Applying them results in a Boolean value that
indicates whether they hold true in this case.
Strings can be compared in the same way.
console.log("Aardvark" < "Zoroaster") // → true
The way strings are ordered is more or less
alphabetic: uppercase letters are always “less” than lowercase ones,
"Z" < "a" is true, and nonalphabetic characters (!, -, and so on)
are also included in the ordering. The actual comparison is based on
the Unicode standard. This standard assigns a number to
virtually every character you would ever need, including characters
from Greek, Arabic, Japanese, Tamil, and so on. Having such numbers is
useful for storing strings inside a computer because it makes it
possible to represent them as a sequence of numbers. When comparing
numeric codes of the characters one by one.
Other similar operators are
than or equal to),
<= (less than or equal to),
== (equal to), and
!= (not equal to).
console.log("Itchy" != "Scratchy") // → true
that is not equal to itself, and that is
NaN (which stands for "not
console.log(NaN == NaN) // → false
NaN is supposed to denote the result of a nonsensical computation,
and as such, it isn’t equal to the result of any other nonsensical
&& operator represents logical
and. It is a binary operator, and its result is true only if both
the values given to it are true.
console.log(true && false) // → false console.log(true && true) // → true
|| operator denotes logical
or. It produces true if either of the values given to it is true.
console.log(false || true) // → true console.log(false || false) // → false
Not is written as an exclamation mark
!). It is a unary operator that flips the value given to it—
When mixing these Boolean operators with arithmetic
and other operators, it is not always obvious when parentheses are
needed. In practice, you can usually get by with knowing that of the
operators we have seen so far,
|| has the lowest precedence, then
&&, then the comparison operators (
==, and so on), and
then the rest. This order has been chosen such that, in typical
expressions like the following one, as few parentheses as possible are
1 + 1 == 2 && 10 * 10 > 50
The last logical operator I will discuss is not unary, not binary, but ternary, operating on three values. It is written with a question mark and a colon, like this:
console.log(true ? 1 : 2); // → 1 console.log(false ? 1 : 2); // → 2
This one is called the conditional operator (or sometimes just ternary operator since it is the only such operator in the language). The value on the left of the question mark “picks” which of the other two values will come out. When it is true, the middle value is chosen, and when it is false, the value on the right comes out.
There are two special values, written
undefined, that are used to denote the absence of a meaningful
value. They are themselves values, but they carry no
Many operations in the language that don’t produce a meaningful value
(you’ll see some later) yield
undefined simply because they have to
yield some value.
The difference in meaning between
null is an accident
where you actually have to concern yourself with these values, I
recommend treating them as interchangeable (more on that in a moment).
Automatic type conversion
console.log(8 * null) // → 0 console.log("5" - 1) // → 4 console.log("5" + 1) // → 51 console.log("five" * 2) // → NaN console.log(false == 0) // → true
When an operator is applied to the “wrong” type of value,
a set of rules that often aren’t what you want or expect. This is
called type coercion. So the
null in the first expression becomes
0, and the
"5" in the second expression becomes
5 (from string
to number). Yet in the third expression,
+ tries string
concatenation before numeric addition, so the
1 is converted to
"1" (from number to string).
When something that
doesn’t map to a number in an obvious way (such as
undefined) is converted to a number, the value
NaN is produced.
Further arithmetic operations on
NaN keep producing
NaN, so if you
find yourself getting one of those in an unexpected place, look for
accidental type conversions.
When comparing values of the same type using
outcome is easy to predict: you should get true when both values are
the same, except in the case of
NaN. But when the types differ,
what to do. In most cases, it just tries to convert one of the values
to the other value’s type. However, when
on either side of the operator, it produces true only if both sides
are one of
console.log(null == undefined); // → true console.log(null == 0); // → false
That last piece of behavior is often useful. When you want to test
whether a value has a real value instead of
can simply compare it to
null with the
But what if you want to test whether
something refers to the precise value
false? The rules for
converting strings and numbers to Boolean values state that
NaN, and the empty string (
"") count as
false, while all the
other values count as
true. Because of this, expressions like
"" == false are also true. For cases like this, where you
do not want any automatic type conversions to happen, there are two
!==. The first tests whether a value is
precisely equal to the other, and the second tests whether it is not
precisely equal. So
"" === false is false as expected.
I recommend using the three-character comparison operators defensively to prevent unexpected type conversions from tripping you up. But when you’re certain the types on both sides will be the same, there is no problem with using the shorter operators.
Short-circuiting of logical operators
|| handle values of different types in a
peculiar way. They will convert the value on their left side to
Boolean type in order to decide what to do, but depending on the
operator and the result of that conversion, they return either the
original left-hand value or the right-hand value.
|| operator, for example, will return the value
to its left when that can be converted to true and will return the
value on its right otherwise. This conversion works as you’d expect
for Boolean values and should do something analogous for values of
console.log(null || "user") // → user console.log("Karl" || "user") // → Karl
This functionality allows the
|| operator to be
used as a way to fall back on a default value. If you give it an
expression that might produce an empty value on the left, the value on
the right will be used as a replacement in that case.
&& operator works similarly, but the other way
around. When the value to its left is something that converts to
false, it returns that value, and otherwise it returns the value on
Another important property of these two
operators is that the expression to their right is evaluated only when
necessary. In the case of
true || X, no matter what
X is—even if
it’s an expression that does something terrible—the result will be
X is never evaluated. The same goes for
false && X,
which is false and will ignore
X. This is called short-circuit
The conditional operator works in a similar way. The first expression is always evaluated, but the second or third value, the one that is not picked, is not.
Such values are created by typing in their name (
"abc"). You can combine and transform values with
operators. We saw binary operators for arithmetic (
%), string concatenation (
+), comparison (
>=), and logic (
||), as well as
several unary operators (
- to negate a number,
! to negate
typeof to find a value’s type).