Let's talk basics of the basics.
Strings are text. They're surrounded by either:
'Hello! I am a string'
"I am also a string"
`Me too. We are all strings`Numbers are... Numbers. They represent numerical value and are always stored as double precision (64 bit) floating point numbers.
10
-1
200192003
5
3.14
123e5 // Scientific notation
123e-5
0x42 // Hexadecimal notationThese are all numbers.
Straightforward, either true, or false
true
falsevar, let, and constVariables store data, whether they're of the String, Number, or Boolean type. They're also used to store more complex data types, but we'll get there later.
var greeting = 'hello';
const MyAge = 29;
let isOldEnoughToParty = true;Running console.log() against any of these variables will print out what their value is:
console.log(greeting); // => 'hello'
console.log(MyAge); // => 29
console.log(isOldEnoughToParty); // truevarBefore ES2015, aka ES6, there was ES5, the older version of JavaScript.
The only way to declare a variable in this version was with using var.
var is a little quirky, because its scope lives at the function level. It can also be redeclared.
var x = 'oh dang';
function MyFunction() {
var x = 10;
var x = 1;
var x = false;
}What's the value of x? At the end of MyFunction(), x is false, but outside of MyFunction(), x is 'oh dang'. This ambiguous behavior should be avoided as much as possible.
Unless you need function scope, do not use var.
let and constUnlike var, let and const are block scoped, and not function scoped.
Take a look at this for loop:
for(var i = 0; i < array.length; i++) {
// Loop!
}
console.log(i); // => array.lengthThe i variable is still able to be accessed outside of the for loop because it's function scoped. If we used let, this would happen instead:
for(let i = 0; i < array.length; i++) {
// Loop!
}
console.log(i); // => undefinedThis is much better because block scoping, while being stricter, is much more maintainable than function scoping. If you had a gigantic function from a legacy project that had var x = ... declared multiple times, it would be pretty difficult to find the value and scope of x.
let and const aren't able to have the same identifiers between themselves or others.
let first = 10;
first += 5;
const first = 20; // => Exception: Identifier 'first' has already been declaredBlock scoping is more strict, so just by looking at where the let/const is being used, you'll be able to understand the scope utilizing much less brainpower :D.
let vs constlet can be reassigned, and const cannot.
let first = 10;
first = 20; // => OK
const second = 1000;
second = 2000; // => Exception: Cannot reassign 'const' valueUnderstand that you can still run methods on const, and those methods can change the value of a const variable.
const myArray = ['raining', 'cats', 'and', 'dogs'];
myArray.pop();
console.log(myArray); // => [ 'raining', 'cats', 'and' ]Just because something is a const does not mean that it's immutable.
Destructuring is a convenient way of getting exactly what you need from an Object or Array.
Instead of:
function onServerResponse(response) {
var body = response.body;
var firstName = body.firstName; // 'Ronny'
var lastName = body.lastName; // 'Rumples'
var occupation = body.occupation; // 'Programmer'
var age = body.age; // 44
//...
}You can grab body with some handy curly brace syntax:
function onServerResponse(response) {
const { body } = response;
const { firstName, lastName, occupation, age } = body;
console.log(firstName); // 'Ronny'
console.log(lastName); // 'Rumples'
console.log(occupation); // 'Programmer'
console.log(age); // 44
//...
}You can go even more levels deep like this:
function onServerResponse(response) {
const { body: {
firstName,
lastName,
occupation,
age
} } = response;
console.log(firstName); // 'Ronny'
console.log(lastName); // 'Rumples'
console.log(occupation); // 'Programmer'
console.log(age); // 44
// Note: Understand that 'body' will be undefined here:
console.log(body); // undefined
}If you wanted to get body along with everything else, you can do this:
function onServerResponse(response) {
const { body: {
firstName,
lastName,
occupation,
age
}, body } = response;
/*
Above, we tell JS we want to pull firstName, lastName, etc from 'body',
but we also tell it that we want 'body' declared, too.
*/
console.log(firstName); // 'Ronny'
console.log(lastName); // 'Rumples'
console.log(occupation); // 'Programmer'
console.log(age); // 44
console.log(body); // { firstName: 'Ronny', lastName: 'Rumples', ... }
}It doesn't just happen within the body of a function either. You can destructure when you're declaring function parameters/arguments too:
function onServerResponse({ body }) {
const { firstName, lastName, occupation, age } = body;
console.log(firstName); // 'Ronny'
console.log(lastName); // 'Rumples'
console.log(occupation); // 'Programmer'
console.log(age); // 44
//...
}If the name isn't a valid JS variable name (has '-' or '.' characters), you can alias it through destructuring like this:
function onServerResponse({ body }) {
// body = { "domain-name": "Google", "google.com": "Established 1998" }
const { 'domain-name': domainName, 'google.com': searchEngineInfo } = body;
console.log(domainName); // 'Google'
console.log(searchEngineInfo); // 'Established 1998'
//...
}Of course, if the name is a valid JS variable name, then you can omit the quotes:
function onServerResponse({ body }) {
const { firstName: first, lastName: last, occupation: job, age: years } = body;
console.log(first); // 'Ronny'
console.log(last); // 'Rumples'
console.log(job); // 'Programmer'
console.log(years); // 44
// Note: 'firstName', 'lastName', 'occupation', and 'age' will all be undefined
//...
}The party doesn't stop with Objects. If you know the array coming just has 2 values, you can destructure like this:
const myArray = ['Hello', 'Clarice'];
const [ hello, clarice ] = myArray;
console.log(hello); // 'Hello'
console.log(clarice); // 'Clarice'Of course, you don't need to name them hello or clarice. You can name them whatever you'd like:
const myArray = ['Hello', 'Clarice'];
const [ greeting, name ] = myArray;
console.log(greeting); // 'Hello'
console.log(name); // 'Clarice'A common usage of destrucuring is with Object.entries, since it returns an array with the Object's key/value pairs in the form of an Array:
const MyObject = {
name: 'Jeff',
personality: 'Wild',
isAwesome: true
};
Object.entries(MyObject).map( ([key, value]) => {
console.log(key); // 'name', 'personality', 'isAwesome'
console.log(value); // 'Jeff', 'Wild', true
})JavaScript now has some really great shorthand and convenience syntax when it comes to Objects.
Look at this excerpt. We used to have to do stuff like this:
function onServerResponse(response) {
var body = response.body;
var firstName = body.firstName; // Judy
var lastName = body.lastName; // Jenson
var age = body.age; // 32
var occupation = body.occupation; // Programmer
return {
firstName: firstName,
lastName: lastName,
age: age,
occupation: occupation
};
}There's quite a bit of repeated code with variables here, and it looks pretty repetitive. If a variable name will be the key of an object, you can just pass that in as the object.
function onServerResponse(response) {
var body = response.body;
var firstName = body.firstName; // Judy
var lastName = body.lastName; // Jenson
var age = body.age; // 32
var occupation = body.occupation; // Programmer
return {
firstName,
lastName,
age,
occupation
};
// returns { firstName: 'Judy', lastName: 'Jenson', age: 32, occupation: 'Programmer' }
}Of course, if we add in destructuring, we can make this even shorter and more compact:
function onServerResponse(response) {
const { firstName, lastName, age, occupation } = response.body;
return {
firstName,
lastName,
age,
occupation
};
}We can make this even shorter with the Object Rest Spread Operator too, assuming that response.body has only the key/value pairs we want to return in a new object:
function onServerResponse(response) {
return { ...response.body };
}But what if response.body has some extraneous information in it? We can still use the Object Rest Spread Operator, but just pick out what we don't want like this:
function onServerResponse(response) {
const { ssn, birthday, ...rest } = response.body;
return { ...rest };
}If you're confused about the syntax, the ... is the Spread Operator. We go into much more detail on this operator in the next chapter.
Defining methods on objects is usually done like this:
var SomeObject = {
performMagic: function(magic) {
console.log('Alakazam! ', magic);
}
};Now we can do this instead:
const SomeObject = {
performMagic(magic) {
console.log('Alakazam! ', magic);
}
};In this section we learned about:
String, Number, and Boolean oh my!var, let, and const, including the differences between all three.Object and Array data types.If anything, this section was really meant to be a quick review on some basic variables and popular ES2015+ features like destructuring.
Ready for the next big challenge? Things get interesting in the next chapter!