Introduction to types
In this section I explain in careful details all the types that JavaScript provides, which I already introduced but I’ll repeat here:
Primitive types
- numbers
- strings
- booleans
- symbol
- null
- undefined
Object types
Any value that’s not of a primitive type (a string, a number, a boolean, a symbol, null or undefined) is an object .
Object types have properties and also have methods that can act on those properties.
The difference between the two is that primitive types store one value, while object types store many properties.
Also, pretty big difference is that primitive types are passed by value but object types are passed by reference .
Tip: arrays are not a type in JavaScript. Arrays are objects. I’ll talk more about arrays in their own section later.
Strings
A string type is a sequence of characters.
It can be also defined as a string literal, which is enclosed in quotes or double quotes:
'A string'
"Another string"
There’s little to no difference in using one or the other. The only difference lies in having to escape the quote character you use to delimit the string:
const test = 'test'
const test = 'te\'st'
const test = 'te"st'
const test = "te\"st"
const test = "te'st"
There are various style guides that recommend always using one style vs the other.
I personally prefer single quotes all the time, and use double quotes only in HTML.
You assign a string value to a variable like this:
const name = 'Flavio'
You can determine the length of a string using the length
property of it:
'Flavio'.length //6
const name = 'Flavio'
name.length //6
This is an empty string: ''
. Its length property is 0:
''.length //0
A single character can be represented in JavaScript using a string with 1 character in it:
'c'.length //1
const character = 'c'
c.length //1
Two strings can be joined using the + operator:
"A " + "string"
You can do this with variables too:
const name = 'Flavio'
"My name is " + name //My name is Flavio
Template literals
Template literals is the term to identify another way to define strings, introduced in 2015. Use backticks instead of single or double quotes:
const a_string = `something`
They are unique because they provide a lot of features that normal strings built with quotes do not, in particular:
- they offer a great syntax to define multiline strings
- they provide an easy way to interpolate variables and expressions in strings
- they allow you to create DSLs with template tags (DSL means domain specific language and it’s, for example, used in React by Styled Components, to define CSS for a component)
Let’s dive into each of these in detail.
Multiline strings
Pre-ES6, to create a string spanning over two lines you had to use the \
character at the end of a line:
const string =
'first part \
second part'
This allows to create a string on 2 lines, but it’s rendered on just one line:
first part second part
To render the string on multiple lines as well, you explicitly need to add \n
at the end of each line, like this:
const string =
'first line\n \
second line'
or
const string = 'first line\n' + 'second line'
Template literals make multiline strings much simpler.
Once a template literal is opened with the backtick, you just press enter to create a new line, with no special characters, and it’s rendered as-is:
const string = `Hey
this
string
is awesome!`
Keep in mind that space is meaningful, so doing this:
const string = `First
Second`
is going to create a string like this:
First
Second
an easy way to fix this problem is by having an empty first line, and appending the trim() method right after the closing backtick, which will eliminate any space before the first character:
const string = `
First
Second`.trim()
Interpolation
Template literals provide an easy way to interpolate variables and expressions into strings.
You do so by using the ${...}
syntax:
const var = 'test'
const string = `something ${var}` //something test
inside the ${}
you can add anything, even expressions:
const string = `something ${1 + 2 + 3}`
const string2 = `something ${foo() ? 'x' : 'y'}`
Escaping
A string can contain escape sequences that can be interpreted when the string is printed, like \n to create a new line:
'I am\na developer'
The backslash is also useful when you need to enter, for example, a quote in a string enclosed in quotes, to prevent the char to be interpreted as a closing quote:
'I\'m a developer'
Common escaping sequences include:
Sequence | Description |
---|---|
\n |
New line character |
\r |
Carriage return character |
\t |
Tab character |
\" |
Double quote character |
\' |
Single quote character |
\\ |
Backslash character |
\uXXXX |
Unicode character |
We’ll talk about Unicode later.
Transform a string into an array using the spread operator
You can expand a string using the spread operator ...
, which creates an array with each character in the string:
const hey = 'hey'
const arrayizedHey = [...hey] // ['h', 'e', 'y']
This operator has some pretty useful applications. The most important one is the ability to use an array as function argument in a very simple way:
const f = (foo, bar) => {}
const a = [1, 2]
f(...a)
String methods
A string value has useful methods attached to it, which we can use to perform a wide variety of operations.
We’ll analyze each one of them in the “Standard Library” section. By Standard Library we mean the built-in features that the language provides. That section goes deep into listing them all and providing nice examples.
Numbers
When you create a variable with a number value, that is assigned a Number type.
JavaScript supports positive and negative numbers:
const one = 1
const minusOne = -1
const bigNumber = 5354576767321
A number can be defined using hexadecimal syntax by using the 0x
prefix:
const thisIs204 = 0xCC //204
There is an octal syntax too, which is removed in strict mode so I won’t talk about it.
We can define decimals too:
const someNumber = 0.2
const pi = 3.14
Internally, JavaScript has just one type for numbers: every number is a float . You might be familiar with other languages that define integers and other number types. JS only has one.
This means one big consequence: some numbers cannot be represented exactly .
What does this mean in practice?
No problem for integers, numbers defined without a decimal part: 1, 2, 100000, 2328348438… up to 15 digits. Starting from 16 digits you’ll have approximation issues.
Decimal numbers are the ones that gives the most problems.
JavaScript stores numbers as floats, and floats cannot be represented with full precision by the computer, technically.
Here’s a simple example of what this means:
2.2*2 //4.4
2.2*20 //44
2.2*200 //440.00000000000006 (???)
2.2*2000 //4400
2.2*20000 //44000
Another example:
0.1 * 0.1
You might expect 0.01
from this operation? No, the result is 0.010000000000000002
.
You might never run into problems but you might, so you need to keep this in mind.
The problem is generally solved by avoiding to process numbers as decimals:
(0.1 * 10) * (0.1 * 10) / 100
But the problem is best avoided by not storing decimals at all, and using calculations to just render numbers as decimals to the user instead of storing them as such.
Booleans
JavaScript defines two reserved words for booleans: true
and false
.
Those are used to create a boolean value.
You can create a boolean using the Boolean() factory function:
const isReal = Boolean(true)
or using the boolean literal syntax:
const isReal = true
Booleans are great for comparisons and to control the flow of a program.
Comparison operations ==
===
<
>
(and so on) return either true or false.
Example:
const a = 1
a === 1 //true
if
, while
statements and other control structures use booleans to determine the flow of the program.
Truthy and falsy values
They don’t just accept true or false, but also accept truthy and falsy values.
Falsy values, values interpreted as false , are
0
-0
NaN
undefined
null
'' //empty string
All the rest is considered a truthy value .
null and undefined
JavaScript defines two special types, which both have only one value assigned: null
and undefined
.
Those are very special.
null
null
is a special value that indicates the absence of a value.
It’s a common concept in other languages as well, can be known as nil
or None
in Python for example.
undefined
undefined
indicates that a variable has not been initialized and the value is absent.
It’s commonly returned by functions with no return
value. When a function accepts a parameter but that’s not set by the caller, it’s undefined.
Symbol
Symbol is a primitive data type of JavaScript, along with string, number, boolean, null and undefined.
It was introduced in ECMAScript 2015, so just a few years ago.
It’s a very peculiar data type. Once you create a symbol, its value is kept private and for internal use.
All that remains after the creation is the symbol reference.
You create a symbol by calling the Symbol()
global factory function:
const mySymbol = Symbol()
Every time you invoke Symbol()
we get a new and unique symbol, guaranteed to be different from all other symbols:
Symbol() === Symbol() //false
You can pass a parameter to Symbol()
, and that is used as the symbol description , useful just for debugging purposes:
console.log(Symbol()) //Symbol()
console.log(Symbol('Some Test')) //Symbol(Some Test)
Symbols are often used to identify object properties.
Often to avoid name clashing between properties, since no symbol is equal to another.
Or to add properties that the user cannot overwrite, intentionally or without realizing.
Examples:
const NAME = Symbol()
const person = {
[NAME]: 'Flavio'
}
person[NAME] //'Flavio'
const RUN = Symbol()
person[RUN] = () => 'Person is running'
console.log(person[RUN]()) //'Person is running'
Symbols are not enumerated, which means that they do not get included in a for..of
or for..in
loop ran upon an object.
Symbols are not part of the Object.keys()
or Object.getOwnPropertyNames()
result.
You can access all the symbols assigned to an object using the Object.getOwnPropertySymbols()
method.
Object
Until now we saw the JavaScript primitive types. They can hold one and just one value associated with them.
Objects are different.
An object is defined using different syntaxes. The simplest one is the object literal :
const car = {}
You can also initialize an object using the Object() global function:
const car = Object({
color: 'blue'
})
The object literal is the simplest syntax.
An object is a collection of properties. Every property can be defined at initialization time, and later retrieved using the dot notation :
const car = {
color: 'blue'
}
car.color //blue
A property has a name, and a value.
A value can be a function , in which case we don’t call it a property, but instead we call it a method .
const car = {
drive: function() {
//do something
}
}
We can “see” it using car.drive
, and we can invoke (run) it by appending the parentheses: car.drive()
.
More on functions later.
Summary of types definition
Here’s a roundup of how you declare each different type in JavaScript:
Strings
const name = String('Flavio')
const name = 'Flavio' //string literal
Numbers
const age = Number(36)
const age = 36 //number literal
Booleans
const male = Boolean(true)
const age = true //boolean literal
Null / undefined
const someProperty = null
const someProperty = undefined
(no literal syntax)
Symbols
const aSymbol = Symbol()
(no literal syntax)
Objects
const person = Object({
name: 'Flavio'
})
const person = { //literal
name: 'Flavio'
}
The typeof operator
As we mentioned in this section, any value has a type assigned. Use the typeof
operator to get a string representation of a type:
typeof 1 //'number'
typeof '1' //'string'
typeof {name: 'Flavio'} //'object'
typeof [1, 2, 3] //'object'
typeof true //'boolean'
typeof undefined //'undefined'
typeof (() => {}) //'function'
typeof Symbol() //'symbol'
JavaScript has no “function” type, and it seems funny that typeof
returns 'function'
when we pass it a function.
It’s one quirk of it, to make our job easier.
Type conversions (casting)
Even if JavaScript is a loosely typed language, you might have the need to convert a value from a type to another.
In JavaScript we have those primitive types:
Number
String
Boolean
Symbol
and the object type:
Object
(plus null
and undefined
, but there’s no point in casting from/to them)
For example, you might want to convert:
- a number to a string
- a string to a number
- a string to a boolean
- a boolean to a string
…and so on.
Here are the techniques you can use to convert from one type to another. I cover the most common cases.
Converting to strings
In general converting from anything to a string is usually a matter of calling the toString()
method on any value, and JavaScript will create a string value corresponding to that type. Or you can pass any value to the String()
global function.
Casting from number to string
Use the String global function, or the Number type toString()
method:
String(10) //"10"
(10).toString() //"10"
Casting from boolean to string
Use the String global function, or the Boolean type toString()
method:
String(true) //"true"
true.toString() //"true"
String(false) //"false"
false.toString() //"false"
Casting from date to string
Use the String global function, or the Date type toString()
method:
String(new Date('2019-01-22'))
//"Tue Jan 22 2019 01:00:00 GMT+0100 (Central European Standard Time)"
(new Date('2019-01-22')).toString()
//"Tue Jan 22 2019 01:00:00 GMT+0100 (Central European Standard Time)"
Special cases with string
String(null) //"null"
String(undefined) //"undefined"
String(NaN) //"NaN"
Converting to numbers
Casting from string to number
We can do this by using the Number()
global function, which is sort of a constructor. We can pass it a string, and JavaScript will figure out how to convert it to a number:
Number("1") //1
Number("0") //0
Strings are trimmed before being converted to numbers:
Number(" 1 ") //1
passing an empty string defaults to 0:
Number("") //0
and to have work with decimals you use a dot:
Number("12.2")
If a string contains invalid characters, it will generate a NaN
.
This are the basics of converting to numbers, but I give a lot more details in how to convert a string to a number in JavaScript. There are other ways to generate numbers from string including parseInt()
, parseFloat()
, Math.floor()
, the unary +
operator.
Casting from boolean to number
Just as we did for string, passing a boolean to Number()
will return either 0 or 1:
Number(true) //1
Number(false) //0
Casting from date to number
If you pass a Date object to Number()
, it will return the date timestamp, which is the best date to number conversion you can get.
Special cases with number
Number(null) //0
Number(undefined) //NaN
Number(NaN) //NaN
Converting to booleans
Any value can be converted to boolean passing it to Boolean()
.
All values will resolve to true
except:
Boolean(false) //false
Boolean(0) //false
Boolean(NaN) //false
Boolean("") //false
Boolean(null) //false
Boolean(undefined) //false
Quiz
Welcome to the quiz! Try to answer those questions, which cover the topics of this module.
You can also write the question/answer into the Discord chat, to make sure it’s correct - other students or Flavio will check it for you!
- what is the main difference between primitive types and objects?
- how can we join two or more strings?
- can we change the value of a string?
- can you explain why we can’t precisely make a simple operation like adding 0.1 and 0.2? Can you make a small, working example of how would you retrieve 0.3 by adding 0.1 and 0.2?
- what is a key feature of template literals that makes us prefer them over quotes when we define a string?
- what is a symbol?
- what is
undefined
? - what is the difference between
null
andundefined
? - is there any difference between an object defined using the object literal syntax, and one created using the
Object()
constructor? - in which different ways can we access the value of a property of an object?
- how is a method different than a function?
- how can you convert the number
2
to a string? - how can you convert the string
'2'
to a number? - how can you tell what type a value is?