JavaScript Types

One of the most important concepts in programming language theory is that of type. A language’s type system puts constraints on what we can and cannot say. What does JavaScript’s type system look like?

What is a Data Type?

A data type is a set of values grouped together because certain operations apply to them. Every programming language seems to have at least numbers, strings, and booleans.

The Eight Types of JavaScript

JavaScript has 8 types: undefined, null, boolean, number, bigint, string, symbol, and object.

Undefined

The type Undefined has one value, undefined. This is the value given to variables declared without initializers. It means that we don’t know, don’t care, or aren’t supposed to know the actual value.

let numberOfPets = 5
let age
numberOfPets          // 5 (bc you said so)
age                   // undefined (HOW DARE YOU EVEN ASK)

Null

The type Null has one value, null. Technically you can use this value for whatever you want, but conventionally people use it as a way to emphatically and explicitly mean there’s really no value.

let supervisor = "None"     // The supervisor's name is "None"
let supervisor = null       // There is absolutely NO supervisor, and
                            // ...we know that for sure.
let supervisor = undefined  // There might be a supervisor, we just
                            // ...don't know or care who it is. Or we
                            // ...are being told it is none of our
                            // ...business.

Boolean

The two boolean values are true and false. Operators producing boolean values are && (“and also”), || (“or else”), and ! (“not”). Try:

3 < 5 && 21 === 8     // false
1 === 2 || 13 > -5    // true
!(3 <= 55)            // false

let sick = false
let weekday = true
let holiday = true
let canSleepIn = sick || !weekday || holiday

let x = 42
let y = -1
let bothPositive = x > 0 && y > 0
let atLeastOneNegative = x < 0 || y < 0
let exactlyOneNegative = x < 0 !== y < 0
let atLeastOneNonPositive = !bothPositive

Number

Here are some examples of numbers:

42              // Forty-two, and example of a “whole number” or “integer”
3.15            // Three and 15 one-hundredths
1_000_000_000   // It’s fine to use underscores in your numbers
2.4434634E9     // 2.443634 times 10 to the 9th
7.538E-23       // 7.538 times 10 to the -23rd
388E12          // 388 times 10 to the 12th

0x3F82          // A hexadecimal literal (base-16), equal to 16258
0b111011010101  // A binary literal (base-2), equal to 3797
0o3571          // An octal literal (base-8), equal to 1913
Decimal, Binary, Octal, Hex

Need a review?
  • Decimal (base-10): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ..., 19, 20, 21, ..., 99, 100, ...
  • Binary (base-2): 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, ...
  • Octal (base-8): 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, ..., 17, 20, ... 77, 100, ...
  • Hex (base-16): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, ..., 19, 1A, 1B, ... 1F, 20, 21, ..., 99, A0, ... FE, FF, 100, ...
JavaScript can represent any base from 2-36, but these four are the only ones that have a special syntax for directly writing numerals in.

Two important things to know:

Number Operations

Learn these by example. You do not need to memorize them all. Try them in a shell yourself. Not all of these operations are commonly used, but it is good to know that they are there.

+89                 // Unary plus (doesn’t really do anything, does it?)
-21                 // This is negation (not to be confused with subtraction)
5 + 8               // Addition
18 - 30             // Subtraction
23.5 * 12           // Multiplication
31 / 7              // Division
37 % 7              // Remainder
22.5 % 5.25         // Remainder even works on non-integers!
3 ** 5              // Exponentiation

Math.E              // Euler’s number, prints as 2.718281828459045
Math.PI             // Half of tau, prints as 3.141592653589793
Math.SQRT1_2        // Square root of ½, prints as 0.7071067811865476
Math.SQRT2          // Square root of 2, prints as 1.4142135623730951
Math.LN2            // Natural log of 2, prints as 0.6931471805599453
Math.LN10           // Natural log of 10, prints as 2.302585092994046
Math.LOG2E          // Log-base-2 of e, prints as 1.4426950408889634
Math.LOG10E         // Log-base-10 of e, prints as 0.4342944819032518

Math.abs(-103)      // Absolute value of -103, namely 103
Math.sqrt(100)      // 10
Math.cbrt(343)      // 7
Math.hypot(3, -4)   // 5
Math.hypot(2, 7, 5) // 8.831760866327848
Math.random()       // Random number between 0 inclusive and 1 exclusive

Math.sin(1)         // Sine of 1 radian
Math.cos(-3)        // Cosine of -3 radians
Math.tan(1.57)      // Tangent of 1.57 radians
Math.asin(0.5)      // The arcsine of 0.5
Math.acos(-1)       // The arccosine of -1
Math.atan(2)        // The arctangent of 2
Math.atan2(4,-3)    // The angle in radians from the x-axis to the vector <-3, 4>
Math.atan2(1,0)     // The angle in radians from the x-axis to the vector <0, 1>
Math.exp(2)         // e to the 2nd power
Math.log(2.718)     // Natural log of 2.718
Math.log2(2048)     // 11

Math.ceil(-5.9)     // -5
Math.ceil(5.9)      // 6
Math.floor(-5.9)    // -6
Math.floor(5.9)     // 5
Math.round(-5.9)    // -6
Math.round(5.9)     // 6
Math.round(2.5)     // 3
Math.round(-2.5)    // -2 (rounding at halves is toward +∞)
Math.trunc(2.5)     // -2 (trunc just removes the fractional part)
Math.trunc(-2.5)    // -2 (... regardless of sign, i.e. “rounds toward 0”)

Math.max(3, -8, 2.9, -2)   // 3
Math.min(3, -8, 2.9, -2)   // -8
Math.min()                 // Infinity
Math.max()                 // -Infinity

Number.isInteger(90)       // true
Number.isInteger(90.3)     // false
Number.isInteger(90.0)     // true

798 .toString(16)           // '31e'
798 .toString(2)            // '1100011110'
798 .toString(8)            // '1436'
798 .toString(30)           // 'qi'
798 .toString(36)           // 'm6'

// Rare operations: you need to know what a two’s complement encodings is
// in order to understand these.

61 & 22             // Bitwise conjunction
894 | 202           // Bitwise disjunction
3 << 5              // Left shift
298332 >> 6         // Arithmetic right shift
-53 >> 3            // Arithmetic right shift of a negative value
-53 >>> 3           // Logical right shift
~34                 // Bitwise complement
~(-35)              // Can you see the relationship between ~ and -?
Exercise: Can you guess why there’s a space before the dot in the toString examples above?

NaN

The number NaN means not a number and results from computations like:

0 / 0                   // NaN
Infinity - Infinity     // NaN
Infinity * 0            // NaN
Infinity / Infinity     // NaN
Math.acos(100)          // NaN

Any arithmetic operation applied to NaN results in NaN. And guess what: NaN is not equal to anything, not even NaN itself!! To to check for NaN, use Number.isNaN():

8 + NaN                 // NaN
NaN === NaN             // false (no kidding!)
Number.isNaN(0 / 0)     // true
Number.isNaN(5 / 0)     // false, it’s infinity
Number.isNaN("dog")     // false, a string is not the same thing as the value NaN
Exercise: Why do you think 5/0 is infinity but 0/0 is NaN? Why do you think Infinity + Infinity is Infinity but Infinity - Infinity is NaN?
Exercise: Wolfram Alpha says acos(-2) actually has a value, so why do you think JavaScript says Math.acos(-2)is NaN?

Size and Precision Limits

Only certain numbers can be represented exactly in JavaScript—the ones representable by the binary64 format of IEEE 754. All other numbers have to be approximated by the nearest representable number. This is a fact of life with computers that store values in fixed-size storage locations.

0.1 + 0.2                   // 0.30000000000000004
0.3 / 0.1                   // 2.9999999999999996
0.17258 * 7                 // 1.2080600000000001
0.1339 * 714                // 95.60459999999999

2987347774829323985         // 2987347774829324000
2987347774829323985 + 100   // 2987347774829324000
2987347774829323985 + 2008  // 2987347774829326000

955 ** 100                  // 1.0007766372740826e+298
955 ** 105                  // Infinity

5.919873e-300               // 5.919873e-300
5.919873e-320               // 5.92e-320
5.919873e-324               // 5e-324
5.919873e-325               // 0

Read more about Numeric Encoding to find out which numbers are exactly representable.

Good to know:

Useful numbers:

JavaScript NameExact ValuePrinted asDescription
Number.NEGATIVE_INFINITY$-\infty$-InfinityNegative infinity
-Number.MAX_VALUE$-2^{1024}+2^{971}$-1.7976931348623157e+308Most negative finite number
Number.MIN_SAFE_INTEGER$-(2^{53}-1)$-9007199254740991The smallest integer $n$ for which $n-1$ and $n-2$ have distinct representations.
-Number.MIN_VALUE$-2^{-1074}$-5e-324Negative representable number closest to zero
Number.MIN_VALUE$2^{-1074}$5e-324Positive representable number closest to zero
Number.MAX_SAFE_INTEGER$2^{53}-1$9007199254740991The largest integer $n$ for which $n+1$ and $n+2$ have distinct representations.
Number.MAX_VALUE$2^{1024}-2^{971}$1.7976931348623157e+308Most positive finite number
Number.POSITIVE_INFINITY$+\infty$InfinityPositive infinity

That safety thing, in more detail:

Test functions:

Each of these functions return a boolean value:

BigInt

A bigint is a different kind of number: it has to be an integer, but its size is technically unbounded (tho if it gets too big your memory can fill up and bad things can happen). You get the arithmentic operations + (addition), -, *, /, **, <<, >>, &, |, ^, ~, and negation. You cannot use the Math operations on them and you cannot mix bigints and numbers!

420n * -5n           // -2100n
75n / 8n             // 9n (bigint division rounds toward zero!)
55n ** 89n           // 78033190670751819287411028871804135604662579206582642179598761630756217530788715355143091589992314168288227641651598476268958393120556138455867767333984375n

// Bigints give full precision, numbers do not!
98n ** 10n           // 81707280688754689024n
98 ** 10             // 81707280688754690000
Exercise: Try 2n ** 10000n in the console. Did id compute quickly?

String

Intuitively, a string is a sequence of characters. In JavaScript we write them surrounded by quotes, apostrophes, or backticks:

"hello"
'hello'
`hello`
"She said 'I don’t think so 😎'... (╯°□°)╯︵ ┻━┻)"
'x = "4"'
"Shall we 🏄‍♀️ or play 🏀?"
"¡¡Olé 🙌!!"
"Ruby was created by まつもと ゆきひろ"
"E hele kāua i Kauaʻi"
'Поехали в Кауаи'
"අපි කවායි වෙත යමු"
'1. f3 e5 g4 ♛h4++'

Basic String Operations

Strings can be concatenated, joined, trimmed, split, and interpolated. You can even check to see is one string is included in another (either at the beginning, end, or anywhere):

"  hello  ".trimStart()     // "hello  "
"  hello  ".trimEnd()       // "  hello"
"  hello  ".trim()          // "hello"

"hello".replace("e", "u")   // "hullo"

let x = 8
'After ${x} comes ${x+1}'   // "After 8 comes 9"

"hello".includes("ell")     // true
"hello".startsWith("h")     // true
"hello".endsWith("w")       // false

const s = "dog"
const t = "house"
const ajin = ["Kei", "Kō", "Izumi", "Okuyama"]

s + t                       // "doghouse"
`${s}${t}`                  // "doghouse"
s.concat(t)                 // "doghouse"
s.repeat(3)                 // "dogdogdog"
"♥️".repeat(8)               // "♥️♥️♥️♥️♥️♥️♥️♥️"
ajin.join("-👻-")           // "Kei-👻-Kō-👻-Izumi-👻-Okuyama"

"Mississippi".split("si")     // [ 'Mis', 's', 'ppi' ]
"😍😨:👍👍👠:🦆".split(":")    // [ "😍😨", "👍👍👠", "🦆" ]
[..."hi 🎃 🏈"]               // [ "h", "i", " ", "🎃", " ", "🏈" ]

[..."👋🏄‍♀️"]                   // [ "👋", "🏄", "", "♀", "" ]

WAIT WHAT HAPPENED WITH THAT LAST ONE THERE?

Internally, strings are not exactly strings of characters, but they feel like they are. To understand strings, we have to go a bit deeper and ask: What is a character?

Characters and Glyphs

A character is just a named, abstract symbol. Examples:

   PLUS SIGN
   CYRILLIC SMALL LETTER TSE
   RECYCLING SYMBOL FOR TYPE-2 PLASTICS
   MUSICAL SYMBOL FERMATA BELOW

Do not confuse a character with a glyph, which is a picture of a character. Two or more characters can share the same glyph (e.g. LATIN CAPITAL LETTER A and GREEK CAPITAL LETTER ALPHA), and one character can have many glyphs (think fonts, e.g., A A A $\mathcal{A}$ $\mathscr{A}$).

Unicode

Unicode is a character set. Other character sets include ASCII, Latin-1, and Windows-1252, but you should always use Unicode. A character set consists of a set of characters each of which has a unique non-negative integer code point. Traditionally, codepoints are given in hex. Here are some examples from Unicode:

     25 PERCENT SIGN
     2B PLUS SIGN
     54 LATIN CAPITAL LETTER T
     5D RIGHT SQUARE BRACKET
     B0 DEGREE SIGN
     C9 LATIN CAPITAL LETTER E WITH ACUTE
    2AD LATIN LETTER BIDENTAL PERCUSSIVE
    39B GREEK CAPITAL LETTER LAMDA
    446 CYRILLIC SMALL LETTER TSE
    543 ARMENIAN CAPITAL LETTER CHEH
    5E6 HEBREW LETTER TSADI
    635 ARABIC LETTER SAD
    784 THAANA LETTER BAA
    94A DEVANAGARI VOWEL SIGN SHORT O
    9D7 BENGALI AU LENGTH MARK
    BEF TAMIL DIGIT NINE
    D93 SINHALA LETTER AIYANNA
    F0A TIBETAN MARK BKA- SHOG YIG MGO
   11C7 HANGUL JONGSEONG NIEUN-SIOS
   1293 ETHIOPIC SYLLABLE NAA
   13CB CHEROKEE LETTER QUV
   2023 TRIANGULAR BULLET
   20A4 LIRA SIGN
   2105 CARE OF
   213A ROTATED CAPITAL Q
   21B7 CLOCKWISE TOP SEMICIRCLE ARROW
   2226 NOT PARALLEL TO
   2234 THEREFORE
   265E BLACK CHESS KNIGHT
  1D111 MUSICAL SYMBOL FERMATA BELOW
  1D122 MUSICAL SYMBOL F CLEF
  1F3C4 SURFER

Unicode code points are traditionally written with U+ followed by four to six hex digits (e.g. U+00C9, U+1D122).

You can browse the entire Unicode character set, and see sample glyphs for each character, at the Unicode Consortium’s Code Charts. The main Unicode site contains a wealth of additional documentation, indexes, and search tools for finding characters. Sample chapters of the Unicode book, including the interesting chapter on East Asian scripts are worth reading.

Also check out the awesome charbase.com and codepoints.net.

You can build a string out of codepoints:

String.fromCodePoint(65, 66, 67)                                   // "ABC"
String.fromCodePoint(1087, 1088, 1080, 1074, 1077, 1090)           // "привет"
String.fromCodePoint(0x4f, 0x68, 44, 32, 128169, 0x1f4a9, 128175)  // 'Oh, 💩💩💯'

You can embed code points in a string. For characters with code points in the range U+0000 to U+007F, use \xhh; in the range U+0000 to U+FFFF use \uhhhh. You can always use \u{...} no matter what the code point is. Examples:

"\x41"       // "A"
"\u0041"     // "A"
"\u{41}"     // "A"
"\u13cd"     // "Ꮝ"
"\u{13cd}"   // "Ꮝ"
"\u{1f451}"  // "👑"
Exercise: What does the string "\x28\u30ce\u25a1\u76ca\u25a1\x29\u30ce\u5f61\u253b\u2501\u253b" look like? For each codepoint, give the name of its corresponding character.

This shows that the backslash character inside a string is special. It combines with the following character(s) to mean something else. The gory details:

Escape SequenceDescription
\xhhThe character with codepoint hh (exactly 2 hex digits)
\uhhhhThe character with codepoint hhhh (exactly 4 hex digits)
\u{h...h}The character with codepoint h...h (between 1 and 6 hex digits, maybe more)
\'The single quote character (\x27)
\"The double quote character (\x22)
\nThe linefeed character (\x0a)
\tThe tab character (\x09)
\bThe backspace character (\x08)
\rThe carriage return character (\x0d)
\fThe formfeed character (\x0c)
\vThe vertical tab character (\x0b)
\\The backslash character itself (\x5c)

Graphemes

Some characters, such as combiners and modifers, are combined with adjancent characters to produce what looks like a single printed character. These multi-character sequences (when valid) make up an extended grapheme cluster. Examples:

Character SequenceGrapheme
U+0052 LATIN CAPITAL LETTER R
U+030A COMBINING RING ABOVE
Latin capital letter R with a ring above
U+0BA8 TAMIL LETTER NA
U+0BBF TAMIL VOWEL SIGN I
நி
Tamil Ni
U+1F6B4 BICYCLIST
U+1F3FE EMOJI MODIFIER FITZPATRICK TYPE-5
🚴🏾
Bicyclist Type-5
U+1F3C4 SURFER
U+1F3FC EMOJI MODIFIER FITZPATRICK TYPE-3
U+200D ZERO-WIDTH JOINER
U+2640 FEMALE SIGN
🏄🏼‍♀
Woman Surfing Type-3
U+1F469 WOMAN
U+200D ZERO-WIDTH JOINER
U+1F52C MICROSCOPE
👩‍🔬
Woman Scientist
U+1F1F1 REGIONAL INDICATOR SYMBOL LETTER L
U+1F1E7 REGIONAL INDICATOR SYMBOL LETTER B
🇱🇧
Flag for Lebanon

String Details

Cool, so multiple characters might be needed to make up a single grapheme. So what is a string? A sequence of characters, or a seqence of graphemes? As long as you are just printing strings, or concantenating, or trimming, or checking whether a string is a substring of another, you probably don’t care. But if you are doing anything like asking for the 5th character, or the substring at position 7 of length 10, then it matters. And the answer to this question is:

Neither.

What?! It’s true: JavaScript strings are sequence of code units, also known as char codes. Not characters. Not graphemes. Code units. What?! Well for the most part, code units look like characters. These all seem to make sense:

const s = "dog"
const t = "house"

s[0]                      // "d"  (indexes start at 0)
s[2]                      // "g"
s[3]                      // undefined  (no error if beyond)
s[-1]                     // undefined
s.length                  // 3

const m = "Mississippi"

m.includes("sis")         // true
m.indexOf("i")            // 1
m.lastIndexOf("i")        // 10
m.indexOf("q")            // -1
m.slice(3, 8)             // "sissi"
m.slice(7, 100)           // "ippi"
m.slice(5 -3)             // "ssi"  (In slice, -1, -2,... count back from end)
m.slice(8)                // "ppi"
m.slice(5, 3)             // ""  (if going backwards, empty)
m.slice(-5, -3)           // 'si'

"hello".padStart(10, "*")  // '*****hello'
"hello".padEnd(10, "*")    // 'hello*****'
"hello".padEnd(10, "-^")   // 'hello-^-^-'

However, internally, a string is made up of code units, and the index positions and length computations and all that depend on this code unit sequence. So what’s a code unit? Well, if your character is in the range U+0000...U+FFFF (inclusive) it gets one code unit. But if your character has a code point beyond FFFF (these are called astral characters no kidding), it gets two code units. So:

"👍👩‍🔬$🇺🇾".length            // 12

The details are tricky, and you can do a lot without knowing them right away. You can find details here in this document on character sets and character encodings.

If you are a little impatient, here’s the break down for this string length computation (without any technical details):
GraphemeCharacterCode PointCode Units
Thumbs UpTHUMBS UP SIGN12807755357, 56397
Woman ScientistWOMAN12810555357, 56425
ZERO WIDTH JOINER82058205
MICROSCOPE12830055357, 56620
Dollar SignDOLLAR SIGN3636
Uruguayan FlagREGIONAL INDICATOR SYMBOL LETTER U12748255356, 56826
REGIONAL INDICATOR SYMBOL LETTER Y12748655356, 56830
String indexing and length-taking are highly advanced topics

Until you have learned about Unicode, UTF encoding schemes, and Unicode normalization, you shouldn’t really be mucking around with the index positions of individual characters or taking the length of strings.

If you do find yourself interviewing for an internship position and someone asks you a question about indexing and lengths, simply ask your interviewer: “may I ignore astral characters and normalization concerns?” They will probably be impressed. Then you can go ahead and assume one code unit per character.

More string topics

Certain string operations that involve arrays and regular expressions (search, match) will be covered later.

Other obscure operations, such as (1) those dealing with character codes, (2) useless ones like charAt (c’mon just use []), and (3) deprecated or non-standard ones, will not be covered at all.

Symbol

Symbols are unique things. Every time you create a symbol, you get a new thing, different from all other symbols. That doesn’t happen with strings!

$ node
> let x = "dog"
> let y = "dog"
> x === y
true
> let a = Symbol()
> let b = Symbol()
> a === b
false

Symbols can have descriptions, but they aren’t good for much other than the fact that they show up when you print the symbol. Having the same description does not make two symbols equal!

$ node
> let i = Symbol("dog")
> let j = Symbol("dog")
> i
Symbol(dog)
> j
Symbol(dog)
> i === j
false
Symbols are kind of an advanced thing

They are just shown here for completeness sake.

Object

A JavaScript object is a value made up by bundling together named properties, each of which has a value. A property is either a non-negative integer or a string or a symbol. A string property does not have to be given in quotes if it is a simple-enough word (that is, with no spaces or other non-word-like characters).

let part = {
  'serial number': '367DRT2219873X-785-11P',
  description: 'air intake manifold',
  'unit cost': 29.95
}

let person = {
  name: "Seán O'Brien",
  country: 'Ireland',
  birth: { year: 1981, month: 3, day: 17 },
  kidNames: {1: 'Ciara', 2: 'Bearach', 3: 'Máiréad', 4: 'Aisling' }
}

You can always access properties with square-bracket notation. If the property name is a simple string without spaces or punctuation or other oddities, you can use dot-notation.

person.country           // 'Ireland'
person['country']        // 'Ireland'
person.birth.year        // 1981
person.birth['year']     // 1981
person['birth'].year     // 1981
person['birth']['year']  // 1981
person.kidNames[4]       // 'Aisling'
person['kidNames'][4]    // 'Aisling'

const x = 'country'
person[x]                // 'Ireland'

Values of non-objects are ”stored directly” while the values of objects are the pointers, not the objects themselves:

sean.png

This is worth repeating

The value of an object is not a property bundle, but rather a pointer to the property bundle.

The syntax for objects is pretty rich:

const seen = false
const metric = 'weight'
const location = { lat: 20, lon: 100}

const info = {
  color: 'blue',   // quotes for string property names not always needed
  "name": 'Ali',   // quotes are okay even if not needed
  seen,            // a shorthand property, same as seen:seen
  21: true,        // non-negative integer properties okay
  [metric]: 88,    // a compputed property: the key is "weight"
  ...location,     // this spreads the properties of location into this object
}

The fact that object values are actually pointers has major ramifications for assignment and equality testing that you absolutely must understand:

const p = {x: 3, y: 5}   // The curly braces CREATE a new object
const q = {x: 3, y: 5}   // The curly braces CREATE a new object
const r = q              // Copy the arrow in box q into the box for r
p !== q                  // Because these two arrows point to different things
q === r                  // Because these two arrows point to the same thing

Try diagramming these variables and objects on your own. You should end up with this:

jsidentityequality.png

Note that p and q refer to different objects, but q and r refer to the same object. We say q and r are identical as the objects they refer to have the same identity. Now you can tell that p and q are not identical, but might they be “equal”? The objects they refer to have the same property values but alas, no, for JavaScript objects, equality and identity are the same.

Prototypes

Like all useful programming languages, JavaScript has a mechanism to express collections of objects that are all related (structurally or behaviorally) to each other, i.e., to make something resembling a new data type.

Every object in JavaScript has a prototype. When looking up properties, the prototype chain is searched. Objects created with the { } syntax get a built-in, global prototype (details below), but if you use Object.create, you can set the new object’s prototype to whatever you want:

const protoCircle = {x: 0, y: 0, radius: 1, color: "black"}
const c1 = Object.create(protoCircle)
c1.x = 4
c1.color = "green" // Now c1.y === 0 and c1.radius === 1

jsobjwithproto.png

Here $c1$ has two own properties: x and color. It has several inherited properties, including y and radius from its own prototype, and a bunch of others from its prototype’s prototype.

Prototypes are very useful when creating a bunch of objects that look or behave similarly:

jsobjswithsharedproto.png

Arrays

An array is a kind of object with numeric properties. Fortunately, JavaScript provides a convenient syntax for them, too:

let a = []
let b = [8, false, [null, 9]]
let days = ["p\u014d\u02bbakahi", "p\u014d\u02bbalua", "p\u014d\u02bbakolu",
    "p\u014d\u02bbah\u0101", "p\u014d\u02bbalima", "p\u014d\u02bbaono",
    "l\u0101pule"
]

arrays1.png

Here are more arrays, an illustration of mixing objects and arrays (very powerful), and the use of the length property to grow and shrink arrays:

let a = []
let b = [1, 5, 25]
let c = new Array()        // Lame way to say [], don't write this
let d = new Array(4, 5, 6) // Lame way to say [4, 5, 6], don't write this
let e = new Array(10)      // 10 cells, all undefined.
let f = a.length
let g = [1, true, [1,2], {x:5, y:6}, "Hi"]
let h = {triple: {a:4, b:"dog", c:[1,null]}, 7: "stuff"}
let i = [h.triple.a, h[7]]

console.log(g[1])      // Prints true
console.log(g[2][0])   // Prints 1
console.log(g.length)  // Prints 5
g[10] = 100            // Makes g[5] through g[9] undefined
console.log(g.length)  // Prints 11
g.length = 2           // Now g is just [1, true]

Here are a few array operators:

let s = "A red boat"
let a = s.split(" ")      // a is ["A", "red", "boat"]
let b = [9, 3, 2, 1, 3, 7]
let c = b.slice(2, 5)     // c is [2, 1, 3]
let d = c.concat(a)       // d is [2, 1, 3, "A", "red", "boat"]
alert(d.join("**"))       // Alerts 2**1**3**A**red**boat
let a = []                // a is an array of length 0
let b = [3, 5]            // b has length 2
b.push(2)                 // Now b is [3, 5, 2]
b.unshift(7)              // Now b is [7, 3, 5, 2]
a.push(3, 10, 5)          // Now a is [3, 10, 5]
a.reverse()               // Now a is [5, 10, 3]
alert(a.pop())            // Alerts 3 and changes a to [5, 10]
alert(a.shift())          // Alerts 5 and changes a to [10]
b.push(a[0], 1)           // b is now [7, 3, 5, 2, 10, 1]
b.sort()                  // b is now [1, 10, 2, 3, 5, 7]

Later, when we see functions, we’ll see the fabulous array operators every, some, find, findIndex, flat, forEach, map, flatMap, filter, reduce, and reduceRight.

Spreading

Sometimes you want to “unpack” an array to use its values individually. Here are some examples:

let a = [2016, 12, 31]
new Date(...a)             // 2017-01-31T08:00:00.000Z
let b = [9, 30]
a.push(...b, 12)           // a is now [2016, 12, 31, 9, 30, 12]
[4, 3, ...b, 6]            // [4, 3, 9, 30, 6]

An expression of the form ...x is called a spread.

Garbage

When you “unhook” an object from all of the variables that reference it, the object becomes garbage and will (eventually) be picked up by the JavaScript garbage collector. It’s important to make sure you don’t hold on to objects longer than necessary, otherwise memory could fill up with all of the new objects you create and the script might stop working.

Other kinds of objects

Functions and Regular Expressions are objects that have special syntax. We’ll see them later.

JavaScript has a set type in its standard library. To build a set, use this syntax:

let artists = new Set(['Rilo Kiley', 'M.I.A.', 'Death Cab for Cutie', 'Jenny Lewis',
  'Santigold', 'The Decemberists', 'Lily Allen', 'The Shins', 'Tegan and Sara',
  'Leona Naess', 'Yeah Yeah Yeahs', 'Regina Spektor', 'Postal Service', 'Feist',
  'Belle and Sebastian', 'Cold War Kids', 'Silversun Pickups', 'Peter Bjorn and John'
])
artists.add('Jaymay')
artists.size // 19
artists.has('Feist') // true

The new operator is something we will see later.

Also, we’ll see the maps later.

And when doing graphics, we’ll encounter the various typed arrays.

The typeof Operator

JavaScript has a quirky typeof operator. Give it an expression and it will give you back a string. It doesn’t always do what you expect.

typeof 101.3             // "number"
typeof false             // "boolean"
typeof "dog"             // "string"
typeof {x:1, y:2}        // "object"
typeof undefined         // "undefined"
typeof null              // "object" ... WTF?!?!?!? THIS IS TOTALLY STUPID
typeof [1, 2, 3]         // "object"
typeof alert             // "function"

Weak Typing

Normally, operators expect operands of a certain type. If an operator doesn’t get operands of the right type, it does conversions to get similar arguments of the right types. This means JavaScript is weakly typed. In a strongly typed language, on the other hand, finding a value of the wrong type generates an error.

When a boolean is expected:

When a number is expected:

When a string is expected:

NOTE: The == and != operators tell you whether their operands are similar-to or not-similar-to each other. Similarity is not the same as equality. These operators are crap and you should never use them. If you want to determine equality, use use === and !== instead. They tell you whether $x$ and $y$ have the same value and the same type.

A value that is false or would be converted to false is called falsy. All other values are truthy. (I did not make up those names.)

Somewhat related: the values undefined and null are called nullish.

Explicit Type Conversion Idioms

Sometimes you will want to do a type conversion yourself. This is a classic example:

let x = prompt("Enter a number")
let y = prompt("Enter another number")
alert(x + y)              // Oops! Concatenation, not arithmetic addition!

There are a few ways to do the string-to-number conversion explicitly:

Advice: Don’t use parseInt or parseFloat.

In general:

Exercise: Up for a challenge? Try return true. Actually, it’s designed for JavaScript experts, but you do want to be an expert some day, right?

Summary

We’ve covered:

  • What we mean by Type in programming
  • The eight types of JavaScript
  • typeof
  • Weak typing
  • Type conversion