Updated September 18, 2019
JavaScript Essentials
This is an introduction and reference guide to JavaScript. This guide is not all encompassing. It exists for people who are already familiar with the basic concepts of programming and want to pick up JavaScript or those who have started learning JavaScript and just want a simple & quick one page reference.
I've put links to further documentation below each topic if you want to dive deeper.
This is a living document. If you have suggestions please let me know!
Misc. Important Things
A few important things that I'll use throughout this guide and you'll see all of the time in JavaScript (JS).
console.log
console.log
is the go-to method of debugging anything in JavaScript. It will log whatever you pass to it to the console - which will be the browser console or node console. It will work in whatever environment runs JavaScript.
It accepts any type of argument and as many as you want.
console.log('hello!');
console.log('hello!', 'goodbye!');
console.log([1, 2, 3], { example: true });
Comments
There are two ways to define comments in JavaScript. //
will comment out a single line and /*
will comment whatever is below it until there is a */
.
// this is a single line comment
/*
this is a multi
line
comment
*/
Value Types
String
- Defined with either
'
or"
- You can typically convert other values to a string by calling
.toString()
on them.
'hello'; // "hello"
'goodbye'; // "goodbye"
Number
- Integers (
1
) and floats (1.2
) parseInt
andparseFloat
to convert values.NaN
represents not a number.
1; // 1
1.2; // 1.2
parseInt('1.2'); // 1
parseFloat('1.2'); // 1.2
parseInt('No'); // NaN
Boolean
- True or false, yes or no
- Basis of all conditional logic
true; // true
false; // false
Array
- An ordered list of items.
let foods = [];
foods.push('pizza');
foods.push('tacos');
foods.push('burgers');
foods; // ['pizza', 'tacos', 'burgers'];
foods[0]; // 'pizza'
foods[foods.length - 1]; // burgers
foods.pop(); // burgers
foods; // ['pizza', 'tacos']
Null
Defined nothingness.
let example = null;
console.log(example); // null
Undefined
- Default value for any variables you declare
- Undefined nothingness
let example;
console.log(example); // undefined
Object
- Building block of everything in JavaScript
- Defined by
{}
- Like a map. Key value pair.
- Can be nested
- Can contain any value type
- JSON is nearly the exact same with some minor differences (no comments allowed)
let info = {
greeting: 'Hello!',
age: 100,
helpful: true,
favoriteFoods: ['pizza', 'tacos'],
name: {
first: 'John',
last: 'Doe',
},
homeTown: undefined,
favoriteCar: null,
};
info.greeting; // 'Hello!';
info['greeting']; // 'Hello!'
info.name; // { first: 'John', last: 'Doe' }
info.helpful; // true
info.helpful = false;
info.helpful; // false
Further Documentation - Objects
Variables
You'll come across three ways to define variables in JavaScript. A variable can be anything - a string, number, function, object, etc. You'll use them all the time, just like in any other programming language.
let
- Allows you to reassign a variable's value but you cannot redefine a variable.
- Value type doesn't matter and can change.
let x = 'hello'
and thenx = 3
is valid.
let x = 'hello';
x = 'goodbye'; // VALID
x = 1; // VALID
let x = 'potato'; // NOT VALID
const
- Read only value
- Exception: object and arrays - you can modify them but you can't reassign them
const x = 'asdf';
x = 'qwerty'; // NOT VALID
const y = [];
y.push('hello!'); // VALID
const z = {};
z.hello = true; // VALID
var
- "Classic" way to define variables. You'll see it in all older code but not used very often (ever?) anymore.
- Lawless way of defining variables
- Scoping can be weird. Use
let
andconst
.
var x; // undefined
x = true; // true
var x = 'this works too';
Operators
Math
// Addition
1 + 1; // 2
// Subtraction
2 - 1; // 1
// Multiplication
3 * 3; // 9
// Division
10 / 2; // 5
// Remainder
6 % 3; // 0
9 % 4; // 1
10 % 4; // 2
String Concatenation
const firstName = 'John';
const lastName = 'Doe';
firstName + lastName; // "JohnDoe"
firstName + ' ' + lastName; // "John Doe"
See "Template Literals" for a better way (in my opinion) to concatenate strings.
Equality
- Can be used for any type
- Be cognizant on more complex types because it might not be checking what you expect
1 === 1; // true
'hello' === 'hello'; // true
1 === 2; // false
'hello' === 'goodbye'; // false
1 !== 1; // false
'hello' !== 'hello'; // false
1 !== 2; // true
'hello' !== 'goodbye'; // true
Relational Operators
Can be used for different value types but typically only used for numbers
1 > 2; // false
1 < 2; // true
2 >= 2; // true
2 <= 2; // true
3 >= 2; // true
3 <= 2; // false
Conditional Statements
If/Else
The way you'll typically write conditional code.
let name = 'John';
if (name.length > 3) {
console.log('hello!');
} else if (name.length >= 0) {
console.log('keep typing!');
} else {
console.log('please enter a name');
}
Switch
Used to easily match values. Make sure to return
or break
when you get a match so you don't continue to the default response.
let color = 'Orange';
switch (color) {
case 'Red':
console.log('go red!');
break;
case 'Blue':
console.log('go blue!');
break;
case 'Orange':
console.log('go orange!');
break;
default:
console.log("sorry, that's not a valid color");
}
Ternary
A quick way to do an inline decision.
let userInfo = { questionNicely: false };
let question = userInfo.questionNicely
? 'What would you like to drink?'
: 'Whatya want, punk?!';
console.log(question); // Whatya want, punk?!
userInfo.questionNicely = true;
question = userInfo.questionNicely
? 'What would you like to drink?'
: 'Whatya want, punk?!';
console.log(question); // What would you like to drink?
Loops
For
The basic way to do anything in a loop. Set your initial variable, set a condition that needs to pass to continue to the loop, and an expression to increment your variable.
for (let i = 0; i < 10; i++) {
console.log(i);
}
/*
0
1
2
3
4
5
6
7
8
9
*/
While
Another way to do a loop that is a bit more flexible/uses a different syntax.
let i = 0;
while (i < 10) {
console.log(i);
i++;
}
/*
0
1
2
3
4
5
6
7
8
9
*/
Functions
A lot of JavaScript is written following functional programming. Basically a function gets an input, does a calculation, and returns an output. You want to avoid mutating (changing) the input.
There are two ways you'll see functions defined.
Traditional Functions
Traditional functions are defined using the function
keyword. They can either be named or anonymous. Typically if you're defining an anonymous function you'll assign it to a variable.
function add(arg1, arg2) {
return arg1 + arg2;
}
const subtract = function (arg1, arg2) {
return arg1 - arg2;
};
add(2, 1); // 3
subtract(2, 1); // 1
Arrow Functions
The new method of defining functions is using arrow notation. I find it to have a more clean syntax and it gives you some more flexibility in how you return values.
You can use implicit returns which mean you can omit the return
keyword if you return a value within parenthesis "()" (this is often used in React/React Native) or if the computation all happens on one line.
You can also omit the parenthesis around a function argument if only one exists.
There are also some different ways that arrow functions handle this
, but I'll let you read the documentation for more info on that.
const add = (arg1, arg2) => {
return arg1 + arg2;
};
const subtract = (arg1, arg2) => arg1 - arg2;
const square = (num) => num * num;
add(2, 1); // 3
subtract(2, 1); // 1
square(2); // 4
Spread/Rest Syntax
This syntax allows us to copy values over easily without having to define each one. It's a great way to make a copy of data. There are other ways to do it but this "syntax sugar" is sweet and used heavily in React/React Native.
Array
const exampleArr = [1, 2, 3];
const secondArr = [...exampleArr, 4];
console.log(exampleArr); // [1, 2, 3]
console.log(secondArr); // [1, 2, 3, 4]
Further Documentation - Spread
Object
const exampleObj = {
greeting: 'hello',
farewell: 'goodbye',
favoriteFood: 'pizza',
};
const person1 = {
...exampleObj,
greeting: 'hi',
};
console.log(person1); //{ greeting: 'hi', farewell: 'goodbye', favoriteFood: 'pizza' }
Function Arguments
const logOnNewLine = (...args) => {
args.forEach((arg) => {
console.log(arg);
});
};
logOnNewLine('hello', 'pizza', 'goodbye');
/*
hello
pizza
goodbye
*/
Destructuring
Related but opposite to the spread operator is destructuring. You can do this for objects and arrays. It's an easy way to pull values off of an object/array.
This is used very often in React/React Native.
Object
const exampleObj = {
greeting: 'hello',
farewell: 'goodbye',
favoriteFood: 'pizza',
};
const { greeting, farewell } = exampleObj;
console.log(greeting, farewell); // hello goodbye
Array
const numbers = [1, 2, 3];
const [first, second] = numbers;
console.log(first, second); // 1 2
Template Literals/String Interpolation
Template literals are a great way to easily incorporate a dynamic value into a string. Below you'll see a comparison on two ways to generate a string.
When using template literals you create the string with a "`" and any dynamic values should be wrapped in a ${}
.
const firstName = 'James';
const lastName = 'Bond';
const legacyGreeting =
'The name is ' + lastName + ', ' + firstName + ' ' + lastName;
const greeting = `The name is ${lastName}, ${firstName} ${lastName}`;
console.log(legacyGreeting); // The name is bond, James Bond
console.log(greeting); // The name is bond, James Bond
Modules
As you write apps you're going to want to split it up among different files to keep your sanity. There are different means to do so but the built in solution in JavaScript is modules.
Export
If you want to share functionality from one file to another you export it. There are two ways to go about this - named and default exports.
For named exports you can either prefix the variable with the export
keyword (my preference) or you can do a single export
that exports an object of all the variables you want to want export.
To do a default export you just use the export default
keywords.
// Name exports
export const myFunction = () => 'hi!';
const myOtherFunction = () => 'goodbye';
export { myFunction, myOtherFunction };
const myDefaultFunction = () => 'potato';
export default myDefaultFunction;
Import
To use exported logic you need to import it from your other file. This is done with the import
keyword.
If importing a named export you use curly braces and use the actual name inside of that object. For default functions you import without the curly braces. Named and default exports/imports can be combined.
Note that you can name a default export whatever you want but you need to use the exact name for a named export.
import exportExampleDefault, {
myFunction,
myOtherFunction,
} from './exportExample.js';
myFunction(); // hi!
myOtherFunction(); // goodbye
exportExampleDefault(); // potato
Modules are much more extensive than what I covered here. Be sure to read the documentation for this.
Promises
Promises are a way for us to wait for asynchronous (async) work - that's work that takes some amount of time. For example: an API request is an async request - we need to wait for the server to respond.
There are two ways to work with promises.
This is a pretty integral part of more complex applications written in JS. I highly encourage you to dive into the documentation a bit further.
Promises
The traditional way is to use .then
and .catch
. Then is used upon success (when a function resolves a value). Catch is used when an error occurs and rejects success.
const myLongRunningFn = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('success!');
} else {
reject(new Error('failure!'));
}
}, 2000);
});
};
const doWork = () => {
myLongRunningFn()
.then((response) => {
console.log(response); //success!
})
.catch((error) => {
console.log(error.message); // failure!
});
};
Async/Await
There's also some syntactic sugar on top of promises to make it read more synchronously.
You define a function to be async using the async
keyword. Once you've done that you can wait for a function to resolve with the await
keyword.
It's important that you handle any potential errors that may occur. To do that you want to wrap your code that uses await
in a try
/catch
block. Catch serves the same purpose as it did in the promise chain above.
const doWork = async () => {
try {
const response = await myLongRunningFn();
console.log(response); //success!
} catch (error) {
console.log(error.message); // failure
}
};
Though this is a lot this just scratches the surface. I think it will get you most of the way there but if you feel I missed something critical please let me know so I can update it!