CuteMachine

Learn JavaScript In 15 Minutes

On Twitter, I often see the question of how best to learn JavaScript. I think the best way to learn anything is to do it. If you want to become a writer, you need to write. If you're going to become a JavaScript developer, you need to develop JavaScript programs.

This article is a new seedling in my Digital Garden; last tended on August 8, 2020. Sign up to my newsletter, and I will let you know when the article has grown to full bloom.

Hello World In JavaScript

The good news is that JavaScript is very approachable. It is straightforward to write your first line of JavaScript code. All you need is a web browser like Firefox. I recommend Firefox over Chrome because it has a multi-line editor, and I trust Mozilla more than Google.

OK. Time to write your first JavaScript program.

Open the developer console by pressing fn-F12 (on Windows and Linux this is probably control-F12). Alternatively, you can right-click in your browser's window to open the context menu and select Inspect Element.

Now that the developer console is open, you can click on the Console tab.

When you are using Firefox, you can open a multi-line editor by pressing command-b. When you are using Chrome, you will only have one line where you can enter JavaScript commands.

Now type console.log('Hello World') and press command-enter when you are in Firefox's multi-line editor, or just enter when you are not.

You should see "Hello World" printed to the console. 🙌 🎉 🥳

Semicolons

JavaScript can automatically insert semicolons for you. This feature is called Automatic Semicolon Insertion (ASI). Because I'm lazy and the semicolon is not improving readability of the code, I prefer not to use them.

JavaScript Comments

// Single-line comments start with two slashes.

/*
    Multi-line comments
    start with a slash followed by an asterisk, and
    end with an asterisk followed by a slash.
*/

You can use two different styles of comments in JavaScript. Single line comments and multi-line comments.

/*
    Do not try to
    /* nest */
    multi-line comments.
    The attempt will yield a syntax error.
*/

You mustn't nest multi-line comments.

Values

You can use underscores _ to make numbers more readable.

42         // 42
typeof 42  // 'number'

1_000_000 * 10  // 10000000

42 is a value. Every value has a type. You can use the typeof operator to find out what the type of value is. The value 42 is of type number.

Here are some more values listed with their types.

typeof 42           // 'number'
typeof 42.5         // 'number'
typeof "42"         // 'string'
typeof '42'         // 'string'
typeof `42`         // 'string'
typeof "😷"         // 'string'
typeof false        // 'boolean'
typeof true         // 'boolean'
typeof {}           // 'object'
typeof []           // 'object', not 'array'!
typeof(() => {})    // 'function', not 'object'!
typeof(BigInt(42))  // 'bigint'
typeof(Symbol(42))  // 'symbol'

You can use the typeof operator with or without parentheses.

typeof 23.5   // 'number'
typeof(23.5)  // ''number

There are two more primitive types in JavaScript: null and undefined

typeof null       // 'object'
typeof undefined  // 'undefined'

Both null and undefined indicate the absence of a value.

Unfortunately, there is a bug in JavaScript. If you apply the typeof to null, you will get object, which is wrong. It should be null.

The type of undefined is undefined, which is correct. You need to remember this as it is a stumbling block for new JavaScript developers.

Truthy And Falsy Values

There are seven falsy values in JavaScript.

false
undefined
null
""
NaN
0
-0

Falsy values can be used in logical expressions. You must know these seven values by heart.

Expressions

We already saw an example of an expression. 42 is a value, and typeof is an operator which only needs one operand. Every time we apply an operator to a value, we have an expression. An expression evaluates to a value. The expression typeof 42 evaluates to the value 'number'.

Here are some more examples of JavaScript expressions:

40 + 2         // 42
1.1 + 0.4      // 1.5

35 - 5         // 30

10 * 5         // 50

100 / 20       // 5

2**3           // 8

6 * 3 - 2      // 16
6 * (3 - 2)    // 6

Logical Expressions

Logical expressions use logical operators such as && or || and always evaluate to a boolean value.

!false         // true
true && true   // true
false && true  // false
false || true  // true

Operators

Operators are used in expressions, as we have already seen. Many operators are rarely used. Only the operators you will likely use are covered here.

The assignment operator = lets you assign a value to a variable or property.

const obj = { foo: 1 }
obj.bar = 42
obj  // { foo: 1, bar: 42 }

For arithmetic expressions, you can use the arithmetic operators +, -, *, /, and exponentiation operator **.

5 + 5   // 10
5 - 3   // 2
5 * 5   // 25
25 / 5  // 5
2 ** 3  // 8

There are also the combined assignment operators +=, -=, *=, and /= which combine an arithmetic operation with an assignment.

let foo
foo = 13
foo -= 3
foo += 11
foo *= 4
foo /= 2
foo  // 42

The modulo operator % gives you the remainder after a division. This operator is often called the remainder operator.

25 % 5  // 0
28 % 5  // 3

The pre- or post-increment operator ++ can be confusing. You probably should avoid them.

let foo = 10
foo = ++foo
foo  // 11

let bar = 10
bar = bar++
bar  // 10

The same applies to pre- or post-decrement operators; avoid them if possible.

let foo = 10
foo = --foo
foo  // 9

let bar = 10
bar = bar--
bar  // 10

Prefer the following code as it needs fewer brain-cycles to read.

let foo = 10
foo = foo + 1

let bar = 10
bar = bar - 1

Negate a number with the unary - operator.

const foo = 10
console.log(-foo)  // -10

Convert a string to a number with the unary + operator. Notice that the first console.log() will print a string and the second a number to the console.

const foo = '10'
console.log(foo)  // '10'
console.log(+foo)  // 10
+'38' + +'4'  // 42

Concatenate two strings with the + operator.

const welcome = 'Hello' + ' ' + 'Lisa'
welcome  // 'Hello Lisa'

The delete operator lets you remove a property from an object.

const obj = {
  foo: 1,
  bar: 2,
  baz: 3
}

obj  // { foo: 1, bar: 2, baz: 3 }

delete obj.bar

obj  // { foo: 1, baz: 3 }

The delete operator can also be used with arrays.

let arr = [1, 2, 3]
delete arr[0]
arr  // [ 'undefined', 2, 3 ]
typeof arr[0]  // 'undefined'

We already saw the typeof operator. It will return the type of the value you pass as an operand.

typeof 42  // 'number'
typeof 'hello'  // 'string'

The instanceof operator takes two operands. The operand on the left must be an object, and the right operand is the class the object should match. The operator returns true if the object is an instance of the class. Otherwise, it returns false. If the right operand is not an object, the operation will throw a TypeError.

const o = {}
o instanceof Object  // true

const a = [1, 2, 3]
a instanceof Array  // true

const r = /abc/
r instanceof RegExp  // true

const f = (x) => x
f instanceof Function  // true

const d = new Date()
d instanceof Date  // true
d instanceof Object  // true

f instanceof Date  // false

f instanceof null  // TypeError

The in operator takes a left- and a right-side operand. The operator evaluates to true if the left-side operand is a property in the right-side object.

const obj = {
  foo: 1,
  bar: 2
}

'foo' in obj  // true
'bar' in obj  // true
'baz' in obj  // false

The in operator can also be used with arrays. The left-hand operand will be compared to the index (converted to a string) of the array.

const arr = ['one', 'two', 'three']
delete arr[0]
"0" in arr  // false
"1" in arr  // true
"2" in arr  // true

The first-defined operator ?? is a pretty new addition to the programming language. It evaluates the first defined operand and returns its value. To understand the following example you need to remember that an empty string '' is falsy in JavaScript.

const obj = { foo: '' }
obj.bar = 'bar'

obj.foo || obj.bar  // 'bar'
obj.foo ?? obj.bar  // ''

The conditional operator ?: is know by most JavaScript developers as the ternary operator, because there is only one operator that takes three operands. It evaluates the first operand and when it is truthy it will evaluate the second operand and return its value. If the first operand is falsy it will evaluate the third operand and return its value.

const isDelighted = true

isDelighted ? 'Yes, please!' : 'No, thanks.'  // 'Yes, please!'

Comparison Operators

You can use the same comparison operators you know from languages like C and Java: <, <=, >, >=, ==, and !=.

10 < 10  // false
10 <= 10 // true
10 == 10  // true
10 != 10  // false

20 > 20  // false
20 >= 20 // true
20 == 20  // true
20 != 20  // false

There are also two comparison operators you probably do not know when you are new to JavaScript. These two operators are called the strict equality operators: === and !==

20 == 20  // true
20 != 20  // false

20 === 20  // true
20 !== 20  // false

So, what is the difference?

It becomes clear with the following example:

20 == '20'  // true
20 != '20'  // false

20 === '20'  // false
20 !== '20'  // true

The strict equality operators does no type conversions, while the non-strict operators convert types to make the comparison possible. I recommend you use only the strict equality operators because it is hard to remember the type conversion rules. Even if you know what you are doing, it will be harder for less savvy developers to understand your code if you use the non-strict equality operators.

Variables

In JavaScript, we use variables to bind a name to a value. There are three keywords with which we can declare such variables. In older versions of JavaScript, there was only the var keyword to declare variables. But you shouldn't use it anymore. You should use the two keywords which were introduced in the ES6 version of the language: let, and const.

Use const if you do not want to reassign a different value to the variable.

const pi = 3.1415
pi  // 3.1415
pi = 42  // typeerror: assignment to constant variable.

Use let if you want to reassign a value to a variable.

// Be a good JavaScript citizen and use uppercase letters for constants like PI

const PI = 3.1415
let radius = 5
let circumference = 2 * PI * radius
circumference  // 31.415000000000003

radius = 10
circumference = 2 * PI * radius // 62.830000000000005

You have to initialize a variable declared with const; otherwise, you will get a SyntaxError.

const bar  // SyntaxError: Missing initializer in const declaration

Variables declared with the keyword let need not be initialized. The variable's value will be 'undefined'.

let foo
typeof foo  // 'undefined'

By convention names of variables and functions are written in camel case. Constants are written with underscores.

function someFunction() {
  const SOME_CONSTANT = 123.45
  
  console.log(SOME_CONSTANT)
}

someFunction()  // 123.45

Block scope

Variables declared with const or let are block scoped. In JavaScript, a code block is delimited with parentheses.

{
  // one block
  const FOO = 42
  FOO  // 42
}
{
  // another block where the variable FOO is unknown
  FOO  // ReferenceError: FOO is not defined
}

Variables declared with the keyword var are not block scoped. Because of the confusing scoping rules of var we do not want to use such declarations in modern JavaScript.

Strings And Template Literals

Strings can be enclosed with single or double-quotes.

const l = 'This is Lisa.'
l  // 'This is Lisa'

const p = 'This is Lisa\'s MacBook'
p  // "This is Lisa's MacBook."

const c = "This is Lisa's MacBook"
c  // "This is Lisa's MacBook."

Strings are immutable in JavaScript.

const l = 'This is Lisa.'

l[0]  // 'T'
l[0] = 'a'
l[0]  // 'T'
l  'This is Lisa'

Besides enclosing strings in single or double-quotes, you can also use a third option: backticks.

const p = `This is Lisa's MacBook`
p  // "This is Lisa's MacBook."

But when you use backticks to delimit a string of characters, you create not a string but a template literal. Template Literals are more potent than regular strings because you can use expressions to create the string value. The expression needs to be enclosed in ${ and }.

let name = 'Lisa'
let device = 'MacBook'

const l = `This is ${name}'s ${device}.`
l  // "This is Lisa's MacBook."

name = 'Tom'
device = 'iPhone'
const t = `This is ${name}'s ${device}.`
t  // "This is Tom's iPhone."
let v = 5
const c = `${v} times ${v} equals ${v * v}.`
c  // '5 times 5 equals 25.'

Template Literals have yet another advantage over ordinary strings. You can use them to create strings that span over multiple lines.

const mls = `This string
spans over
multiple
lines.`

console.log(mls)
// 'This string
// spans over
// multiple
// lines.'

Arrays

Arrays are list-like objects. You can store values of any type in an array. To create an array just enclose the values you want to store in that array and separate these with commas.

const points = [
  { x: 1, y: 1 },
  { x: 2, y: 2 },
  { x: 3, y: 3 }
]
const arr = ['foo', 'bar', 42]
arr  // [ 'foo', 'bar', 42 ]

You access the values by providing an index. The index of the first element is 0, not 1!

arr[0]  // 'foo'
arr[2]  // 42

Every array has a length property which will the amount of values stored in an array.

arr.length  // 3

You can use the pop() method to remove the last element of the array. There is also a push() method which allows to add a value at the end of the array.

arr.pop()  // 42
arr  // [ 'foo', 'bar' ]

If you try to assign a new value to the variable arr you'll get a TypeError because the variable was defined with const. Therefore the reference cannot be reassigned. Though you can change the contents of the array.

arr = []  // TypeError: Assignment to constant variable.

To change a specific value of the array just use its index within the array.

arr[1] = 'baz'
arr  // [ 'foo', 'baz' ]

You can get all indices and values of an array.

Object.keys(arr)  // [ '0', '1' ]
Object.values(arr)  // [ 'foo', 'baz' ]

You can add new values with an index that did not exist before in the array. Any unused indexes in-between will be filled with 'undefined' values.

arr[3] = 'boom'  // 'boom'
arr  // [ 'foo', 'baz', 'undefined', 'boom' ]
typeof arr[2]  // 'undefined'

You can nest arrays within arrays. After all, arrays are also only objects.

arr[2] = [1, 2, 3]
arr  // [ 'foo', 'baz', [ 1, 2, 3 ], 'boom' ]

Functions

You can use function declarations to create functions.

function greet() {
  return 'Hello'
}

greet()  // 'Hello'

You can also use function expressions to create functions.

const sayHello = function() {
  return 'Hello'
}

sayHello()  // 'Hello'

If you have the need to call a function with parameters you can add arguments to your functions. You can even set default values.

function greet(greeting = 'Hello', name = 'nobody') {
  return `${greeting} ${name}`
}

greet()  // 'Hello nobody'

Since the ES6 version of JavaScript you can write functions expressions with so-called arrow functions. Arrow functions are always anonymous functions as you cannot name them.

const greet = (greeting = 'Hello', name = 'nobody') => {
  return `${greeting} ${name}`
}

greet()  // 'Hello nobody'

There is also a shorter version for simple functions where you do not need a full function body.

const greet = (greeting = 'Hello', name = 'nobody') => `${greeting} ${name}`

greet()  // 'Hello nobody'

Arrow functions with exactly one parameter do not need parentheses around the parameter.

const double = x => x * 2
double(4)  // 8

Closures

You can use closures because it is perfectly find to return a function from a function in JavaScript. It is also perfectly fine to use anonymous functions. In fact all arrow functions are anonymous functions in JavaScript.

function adder(x) {
  return function(y) {
    return x + y
  }
}

const addThree = adder(3)
const addFive = adder(5)

addThree(1)  // 4
addFive(10)  // 15
addThree(addFive(4))  // 12

In the above code adder() returns a new function that remembers x (closes over x).

You can write the adder() function in a more concise way using arrow functions.

const adder = x => y => x + y

Immediately Invoked Function Expression (IIFE)

You will often hear the term Immediately Invoked Function Expression (IIFE). The IIFE pattern is quite handy to execute some JavaScript snippets in a browser's console. It declares an anonymous function and calls it immediately.

(function() {
  console.log('Hello from IIFE')
})()

Objects

The easiest way to create objects in JavaScript is to use the object literal syntax. We cannot change the reference because we used the const keyword to define the variable obj. But we sure can add properties to the object itself because obj is not constant.

const obj = {}

// obj = {}  // TypeError: Assignment to constant variable.

obj.fooValue = 42
obj  // { fooValue: 42 }

If you try to access a property value that does not exist, you will get a TypeError.

const obj = { foo: 42 }
obj.foo
obj.bar  // 'undefined'
typeof obj.bar // 'undefined'
obj.bar.baz  // TypeError: Cannot read property 'baz' of undefined

Object properties can be accessed in two ways. With the dot notation, as we have seen above and with using brackets.

const FOO = 'foo'
const obj = { foo: 42 }

obj.foo     // 42
obj['foo']  // 42
obj[FOO]    // 42

Since ES2020, you can guard the property access if you are unsure whether a property exists with the optional chaining operator ?..

const obj = { foo: 42 }
obj.bar?.baz  // No TypeError

The optional chaining operator also works with arrays and functions.

You can add methods to the object obj easily.

const obj = { fooValue: 42 }
obj.fooMethod = () => console.log('hello from fooMethod: ', this.fooValue)
obj.barMethod = function() { console.log('hello from barMethod: ', this.fooValue)}
obj  // { fooValue: 42, fooMethod: [Function], barMethod: [Function] }

But when you call these methods, you will see a substantial difference you need to be aware of.

obj.fooMethod()  // 'hello from fooMethod: ' undefined
obj.barMethod()  // 'hello from barMethod: ' 42

Because we used the arrow function syntax to add fooMethod() we method does not have access to obj through the this keyword.

The this keyword is used to access a method's execution context in JavaScript.

On the other hand, if we use the standard function expression syntax with the keyword function, we get access to obj automatically because the method's execution context is bound to obj. Because barMethod()'s execution context is bound to the object, it can access the fooValue and print it to the console.

The execution context of fooMethod() and barMethod() are not the same. This difference is why we do get different results when printing fooValue to the console. There is no fooValue in the execution context of fooMethod().

Let's look at an example of how we can use different execution contexts for a method print() to make the concept of the this keyword understandable.

const foo = { text: 'foo context'}
const bar = { text: 'bar context'}

function print() {
  console.log(this.text)
}

const boundToFoo = print.bind(foo)
const boundToBar = print.bind(bar)
boundToFoo()  // 'foo context'
boundToBar()  // 'bar context'

If we don't want to create new functions through the bind() method, we can use call() instead.

print.call(foo)  // 'foo context'
print.call(bar)  // 'bar context'

You cannot rebind the this for arrow functions.

Generally speaking, I would recommend using standard function expressions for object methods and callback functions. For anything else, use arrow functions because they are more readable.

Flow Control

Conditional clauses

The logical not operator is a plain exclamation mark !.

if (!false)
  console.log('true')  // 'true'

It is frowned upon to use the if statement without blocks. The below notation is better.

if (!false) {
  console.log('true')  // 'true'
}

Statement blocks are even more important when we add else clauses.

const foo = 42

if (foo > 50) {
  console.log('foo is greater than 50')  // 'true'
} else if (foo < 50) {
  console.log('foo is less than 50')  // 'true'
}

Many developers try to avoid switch statements. I love them because they are easy to read. If you do not end the case section with a break statement, it will fall through to the next case. In the code below, you can write the up action in lowercase, and it would still write go up to the console.

const action = 'UP'

switch (action) {
  case 'up':
  case 'UP':
    console.log('go up')
    break
  case 'DOWN':
    console.log('go down')
    break
  default:
    console.log('stay where you are')
    break
}

It is good practice to add a break to the default section because default doesn't have to be the last section in a switch statement.

Loops

A simple while loop that counts from 1 to 3.

let num = 0
while (num < 3) {
  num = num + 1  // num++ or num += 1 would also work
  console.log(num)
}

// 1
// 2
// 3

There is also a dowhile loop but you rarely see it used.

Sometimes you see classical for loops as you find them in C or Java, for example.

for (let num = 1; num <= 3; num = num + 1) {
  console.log(num)
}

// 1
// 2
// 3

But you do not see the above loop constructs very often in JavaScript codebases anymore. The main reason is that most applications transform data from one structure into another. To do this, we iterate through iterable data structures. To facilitate this, the ES6 version of JavaScript introduced a new loop statement, the forof loop.

A string in JavaScript is an example of an iterable object.

for (let c of 'hello') {
  console.log(c)
}

// 'h'
// 'e'
// 'l'
// 'l'
// 'o'

Here is another example that iterates through an array with the forof loop.

const arr = [1, 2, 3]

for (let a of arr) {
  console.log(a)
}

// 1
// 2
// 3

To be continued soonish.

References

Inspired by Tyler Neylon's Learn Lua in 15 Minutes.

Posted on CuteMachine in javascript.

Jo's Profile ImageWritten by Jo who lives and works in Frankfurt building digital doodah. Stalk him on Twitter.

TOS • Privacy • Disclaimer