forked from marijnh/Eloquent-JavaScript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
01_values.txt
622 lines (509 loc) · 23.7 KB
/
01_values.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
:chap_num: 1
:prev_link: 00_intro
:next_link: 02_program_structure
:docid: values
= Values, Types, and Operators =
[chapterquote="true"]
[quote, Master Yuan-Ma, The Book of Programming]
____
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.
____
(((Yuan-Ma)))(((Book of Programming)))(((binary
data)))(((data)))(((bit)))(((memory)))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.
(((CD)))(((signal)))Bits are any kind of two-valued things, usually
described as zeros 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.
(((binary number)))(((radix)))(((decimal number)))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 ((digit))s, 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 below 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.
== Values ==
(((memory)))(((volatile data storage)))(((hard drive)))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.
image::img/bit-sea.png[alt="The Ocean of Bits"]
To be able to work with such quantities of bits without getting lost,
you can separate them into chunks that represent pieces of
information. In a JavaScript environment, those chunks are called
_((value))s_. Though all values are made of bits, they play different
roles. Every value has a ((type)) that determines its role. There are
six basic types of values in JavaScript: numbers, strings, Booleans,
objects, functions, and undefined values.
(((garbage collection)))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.
This chapter introduces the atomic elements of JavaScript programs,
that is, the simple value types and the operators that can act on such
values.
== Numbers ==
(((syntax)))(((number)))(((number,notation)))Values of the
_number_ type are, unsurprisingly, numeric values. In a JavaScript
program, they are written as follows:
[source,javascript]
----
13
----
(((binary number)))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.
(((number,representation)))(((bit)))JavaScript uses a fixed
number of bits, namely 64 of them, to store a single number value.
There are only so many patterns you can make with 64 bits, which means
that the amount of different numbers that can be represented is
limited. For _N_ decimal ((digit))s, the amount of numbers that can be
represented is 10^_N_^. Similarly, given 64 binary digits, you can
represent 2^64^ different numbers, which is about 18 quintillion (an
18 with 18 zeros after it). This is a lot.
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.
(((sign)))(((floating-point number)))(((fractional number)))(((sign bit)))Not
all whole numbers below 18 quintillion fit in a JavaScript number,
though. Those bits also store negative numbers, so one bit indicates
the sign of the number. A bigger issue is that nonwhole numbers must
also be represented. To do this, some of the bits are used to store
the position of the decimal point. The actual maximum whole number
that can be stored is more in the range of 9 quadrillion (15 zeros),
which is still pleasantly huge.
(((number,notation)))Fractional numbers are written by using a
dot.
[source,javascript]
----
9.81
----
(((exponent)))(((scientific notation)))(((number,notation)))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:
[source,javascript]
----
2.998e8
----
That is 2.998 × 10^8^ = 299,800,000.
(((pi)))(((number,precision of)))(((floating-point
number)))Calculations with whole numbers (also called _((integer))s_)
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.
=== Arithmetic ===
(((syntax)))(((operator)))(((binary
operator)))(((arithmetic)))(((addition)))(((multiplication))) The main
thing to do with numbers is arithmetic. Arithmetic operations such as
addition or multiplication take two number values and produce a new
number from them. Here is what they look like in JavaScript:
[source,javascript]
----
100 + 4 * 11
----
(((operator,application)))(((asterisk)))(((plus
character)))(((pass:[*] operator)))(((+ operator)))The `+` and `*`
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.
(((grouping)))(((parentheses)))(((precedence)))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.
[source,javascript]
----
(100 + 4) * 11
----
(((dash character)))(((slash
character)))(((division)))(((subtraction)))(((minus)))(((-
operator)))(((/ operator)))For subtraction, there is the `-` operator,
and division can be done with the `/` operator.
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
addition. The `/` operator has the same precedence as `*`. Likewise
for `+` and `-`. 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.
(((modulo operator)))(((division)))(((remainder operator)))(((%
operator)))There is one more arithmetic operator, which you might not
immediately recognize. The `%` symbol is used to represent the
_remainder_ operation. `X % Y` is the remainder of dividing `X` by
`Y`. For example, `314 % 100` produces `14`, and `144 % 12` gives `0`.
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.
=== Special numbers ===
(((number,special values)))There are three special values in
JavaScript that are considered numbers but don't behave like normal
numbers.
(((infinity)))The first two are `Infinity` and `-Infinity`, which
represent the positive and negative infinities. `Infinity - 1` is
still `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`.
(((NaN)))(((not a number)))(((division by zero)))`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.
== Strings ==
(((syntax)))(((text)))(((character)))(((string,notation)))(((single-quote
character)))(((double-quote character)))(((quotation mark)))The next
basic data type is the _((string))_. Strings are used to represent
text. They are written by enclosing their content in quotes.
[source,javascript]
----
"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.
(((line break)))(((newline character)))Almost anything can be put
between quotes, and JavaScript will make a string value out of it. But
a few characters are more difficult. You can imagine how putting
quotes between quotes might be hard. _Newlines_ (the characters you
get when you press Enter) also can't be put between quotes. The string
has to stay on a single line.
(((escaping,in strings)))(((backslash character)))To make it possible to include
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:
[source,javascript]
----
"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 “++A newline
character is written like "\n".++” can be expressed:
[source,javascript]
----
"A newline character is written like \"\\n\"."
----
(((+ operator)))(((concatenation)))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 `"concatenate"`:
[source,javascript]
----
"con" + "cat" + "e" + "nate"
----
There are more ways of manipulating strings, which we will discuss
when we get to methods in link:04_data.html#methods[Chapter 4].
== Unary operators ==
(((operator)))(((typeof operator)))(((type)))Not all operators are
symbols. Some are written as words. One example is the `typeof`
operator, which produces a string value naming the type of the value
you give it.
[source,javascript]
----
console.log(typeof 4.5)
// → number
console.log(typeof "x")
// → string
----
[[console.log]]
(((console.log)))(((output)))(((JavaScript console)))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
depend on the JavaScript environment you use to run it.
(((negation)))(((- operator)))(((binary operator)))(((unary
operator)))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.
[source,javascript]
----
console.log(- (10 - 2))
// → -8
----
== Boolean values ==
(((Boolean)))(((operator)))(((true)))(((false)))(((bit)))Often,
you will need a value that simply distinguishes between two
possibilities, like “yes” and “no” or “on” and “off”. For this,
JavaScript has a _Boolean_ type, which has just two values: true and
false (which are written simply as those words).
=== Comparisons ===
(((comparison)))Here is one way to produce Boolean values:
[source,javascript]
----
console.log(3 > 2)
// → true
console.log(3 < 2)
// → false
----
(((comparison,of numbers)))(((> operator)))(((< operator)))(((greater
than)))(((less than)))The `>` and `<` 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.
[source,javascript]
----
console.log("Aardvark" < "Zoroaster")
// → true
----
(((comparison,of strings)))The way strings are ordered is more or less
alphabetic: uppercase letters are always “less” than lowercase ones,
so `"Z" < "a"` is true, and non-alphabetic 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
strings, JavaScript goes over them from left to right, comparing the
numeric codes of the characters one by one.
(((equality)))(((>= operator)))(((pass:[<=] operator)))(((==
operator)))(((!= operator)))Other similar operators are `>=` (greater
than or equal to), `<=` (less than or equal to), `==` (equal to), and
`!=` (not equal to).
[source,javascript]
----
console.log("Itchy" != "Scratchy")
// → true
----
(((comparison,of NaN)))(((NaN)))There is only one value in JavaScript
that is not equal to itself, and that is `NaN`, which stands for “not
a number”.
[source,javascript]
----
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
computations.
=== Logical operators ===
(((reasoning)))(((logical operators)))There are also some operations
that can be applied to Boolean values themselves. JavaScript supports
three logical operators: _and_, _or_, and _not_. These can be used to
“reason” about Booleans.
(((&& operator)))(((logical and)))The `&&` operator represents logical
_and_. It is a binary operator, and its result is true only if both
the values given to it are true.
[source,javascript]
----
console.log(true && false)
// → false
console.log(true && true)
// → true
----
(((|| operator)))(((logical or)))The `||` operator denotes logical
_or_. It produces true if either of the values given to it is true.
[source,javascript]
----
console.log(false || true)
// → true
console.log(false || false)
// → false
----
(((negation)))(((! operator)))_Not_ is written as an exclamation mark
(`!`). It is a unary operator that flips the value given to it—`!true`
produces `false` and `!false` gives `true`.
(((precedence)))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
comes `&&`, 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
necessary:
[source,javascript]
----
1 + 1 == 2 && 10 * 10 > 50
----
(((conditional execution)))(((ternary operator)))(((?:
operator)))(((conditional operator)))(((colon character)))(((question
mark)))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:
[source,javascript]
----
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.
== Undefined values ==
(((undefined)))(((null)))There are two special values, written `null`
and `undefined`, that are used to denote the absence of a meaningful
value. They are themselves values, but they carry no
information.
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 `undefined` and `null` is an accident
of JavaScript's design, and it doesn't matter most of the time. In the cases
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 ==
(((NaN)))(((type coercion)))In the introduction, I mentioned that
JavaScript goes out of its way to accept almost any program you give
it, even programs that do odd things. This is nicely demonstrated by
the following expressions:
[source,javascript]
----
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
----
(((+ operator)))(((arithmetic)))(((pass:[*] operator)))(((-
operator)))When an operator is applied to the “wrong” type of value,
JavaScript will quietly convert that value to the type it wants, using
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).
(((type coercion)))(((number,conversion to)))When something that
doesn't map to a number in an obvious way (such as `"five"` or
`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.
(((null)))(((undefined)))(((comparison,of undefined values)))(((==
operator)))When comparing values of the same type using `==`, the
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,
JavaScript uses a complicated and confusing set of rules to determine
what to do. In most cases, it just tries to convert one of the values
to the other value's type. However, when `null` or `undefined` occurs
on either side of the operator, it produces true only if both sides
are one of `null` or `undefined`.
[source,javascript]
----
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 `null` or `undefined`, you
can simply compare it to `null` with the `==` (or `!=`) operator.
(((type coercion)))(((Boolean,conversion to)))(((=== operator)))(((!==
operator)))(((comparison)))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 `0`,
`NaN`, and the empty string (`""`) count as `false`, while all the
other values count as `true`. Because of this, expressions like `0 ==
false` and `"" == false` are also true. For cases like this, where you
do _not_ want any automatic type conversions to happen, there are two
extra operators: `===` and `!==`. 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 ===
(((type coercion)))(((Boolean,conversion to)))(((operator)))The
logical operators `&&` and `||` 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)))The `||` 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
other types.
[source,javascript]
----
console.log(null || "user")
// → user
console.log("Karl" || "user")
// → Karl
----
(((default value)))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)))The `&&` 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
its right.
(((short-circuit evaluation)))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
true, and `X` is never evaluated. The same goes for `false && X`,
which is false and will ignore `X`. This is called _short-circuit
evaluation_.
(((ternary operator)))(((?: operator)))(((conditional operator)))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.
== Summary ==
We looked at four types of JavaScript values in this chapter: numbers,
strings, Booleans, and undefined values.
Such values are created by typing in their name (`true`, `null`) or
value (`13`, `"abc"`). You can combine and transform values with
operators. We saw binary operators for arithmetic (`+`, `-`, `*`, `/`,
and `%`), string concatenation (`+`), comparison (`==`, `!=`, `===`,
`!==`, `<`, `>`, `<=`, `>=`), and logic (`&&`, `||`), as well as
several unary operators (`-` to negate a number, `!` to negate
logically, and `typeof` to find a value's type) and a ternary
operator (`?:`) to pick one of two values based on a third value.
This gives you enough information to use JavaScript as a pocket
calculator, but not much more. The
link:02_program_structure.html#program_structure[next chapter] will
start tying these expressions together into basic programs.