JavaScript is what everyone calls the language, but the official name of JavaScript is ECMAScript. That name comes from the standards organization Ecma, which manages the language standard. ECMAScript 1 (June 1997) was the first version of the JavaScript language standard.
Up until now, you've mostly been writing ECMAScript 5. ES5 is comfortable and familiar, but ES6 gives us a lot of great new features, which we'll start learning about this week.
We"ve learned that scope is the area of code in which a variable or value can be accessed.
We already know that variables declared (using the keyword var
) inside of a function will remain scoped to that function and hoisted to the top of that function scope. In other words, it won"t be accessible outside of the function.
In short we have 2 scopes, global and function scope.
ES6 gives us two new variable keywords: let
and const
. These two variable keywords introduce block scope. This means the variable will be confined to the scope of a block that it is defined in, such as an if
statement or for
loop and will not be accessible outside of the opening and closing curly braces of the block.
let
and const
are block-scoped, their scopes are the innermost enclosing blocks. let
and const
behave more strictly and throw more exceptions (e.g. when you access their variables inside their scope before they are declared)function blockScoping() {
if (true) {
// this will throw an error
const x = 24;
let y = 10;
// this works
// var x = 24;
// var y = 10;
}
return { x: x, y: y };
}
var
, let
and const
statements are not hoisted to the top of their enclosing scope.function temporalDeadZone() {
console.log(myVar);
console.log(myLet);
console.log(myConst);
var myVar = "var";
// you can use variables before they"re defined with let and const
let myLet = "let";
const myConst = "const";
return { myVars, myLets, myConsts };
}
let
and const
over var
in morder JS programming is that we want to avoid a variable that is undefined.let
can be reassigned, whereas variables declared with const
cannot.const
, the contents of that array or object can be changed, but that variable name will always point to that same piece of memory.const obj = { a: 1, b: 2 };
obj.b = 3;
// obj: {a: 1, b: 3}
Object shorthand is a way of declaring an object's properties and those properties values quickly and easily.
Intuitive and flexible destructuring of Objects into in dividual variables during assignment.
function shorthandPropertyNames() {
const red = Math.floor(Math.random() * 256);
const green = Math.floor(Math.random() * 256);
const blue = Math.floor(Math.random() * 256);
return { red, green, blue };
// instead of
return {
red: red,
green: green,
blue: blue,
};
}
console.log(shorthandPropertyNames());
Summary: We can assign a property's name and it's value to an object using a variable. The variable name becomes the property
and the variables data will become the property value
.
bird
.const name = "Parrot";
const colors = ["Red", "Green", "Blue", "Yellow"];
const bird = {
name: name,
colors: colors,
};
console.log(bird);
bird
such that a property talons
is true
. Use object property shorthand.const name = 'Parrot'
const colors = ['Red', 'Green', 'Blue', 'Yellow']
const talons = // CHANGE ME
const bird = {
name: name,
colors: colors,
// CHANGE ME
}
console.log(bird)
vietnam
using the variables capital
& continent
. Use shorthand.const capital = "Hanoi";
const continent = "Asia";
const vietnam = {
// CHANGE ME
};
console.log(vietnam);
car
using the variables wheelsCount
, doorsCount
, & color
as property shorthand.const wheelsCount = 4;
const doorsCount = 4;
const color = "black";
const car = {
// CHANGE ME
};
console.log(car);
Destructuring is a way of grabbing properties off of an object and sticking them inside variables.
// Object destructuring
const obj = { first: "Jane", last: "Doe" };
const { first, last } = obj; // first = "Jane"; last = "Doe"
const { first: f, last: l } = obj; // f = "Jane"; l = "Doe"
const state = { counter: 1, list: ["a", "b"] };
// no object destructuring
const list = state.list;
const counter = state.counter;
// object destructuring
const { list, counter } = state;
// Array destructuring
const iterable = ["a", "b"];
const [x, y] = iterable; // x = "a"; y = "b"
Pick what you need
If you destructure an object, you mention only those properties that you are interested in:
const { x: x } = { x: 7, y: 3 }; // x = 7
If you destructure an Array, you can choose to only extract a prefix:
const [x, y] = ["a", "b", "c"]; // x="a"; y="b";
Another great feature is the rest destructuring. It is often used for splitting out a part of an object, but keeping the remaining properties in another object. MDN: Rest parameters
const state = { counter: 1, list: ["a", "b"] };
// rest destructuring
const { list, ...rest } = state;
console.log(rest);
// output: { counter: 1 }
console.log(list);
// output: ["a", "b"]
The spread operator comes with three ...
, but shouldn"t be mistaken for the rest operator. It depends on the context where it is used. Used within a destructuring (see above), it is as rest operator. Used somewhere else it is a spread operator. MDN: Spread syntax
let arr = [-1, 5, 11, 3];
console.log(Math.max(...arr));
Another example to append an array to another array:
const arr1 = ["a", "b"];
const arr2 = ["c", "d"];
arr1.push(...arr2);
// arr1 is now ["a", "b", "c", "d"]
Or to concatenate Arrays:
const x = ["a", "b"];
const y = ["c"];
const z = ["d", "e"];
const arr = [...x, ...y, ...z]; // ["a", "b", "c", "d", "e"]
Many functions will take objects as their arguments. When our functions accept an argument as their parameter, then we'll often want to extract the objects properties. We can do so more easily by using:
obj
keys, x
, y
and z
on one line.function getAverage(obj) {
return Math.floor((x + y + z) / 3.0); // CHANGE ME
}
getAverage({ x: 3.6, y: 7.8, z: 4.3 });
city
, country
and street
variables so that the getAddress()
returns true
.function getAddress(obj) {
return city === "HCMC" && country === "Vietnam" && street === "Ton Dan"; // CHANGE ME
}
getAddress({
city: "HCMC",
country: "Vietnam",
address: {
number: 12,
street: "Ton Dan",
district: "4",
},
});
function objectifyElements(arr) {
return { first, second, third }; // CHANGE ME
}
objectifyElements([0, 1, 2, 3, 4, 5, 6, 7, 8]).fourth === 4;
getFoodItems().mangos === 'mangos'
returns true
.function getFoodItems() {
const food = [
["carrots", "beans", "peas", "lettuce"],
["apples", "mangos", "oranges"],
["cookies", "cake", "pizza", "chocolate"],
];
const carrots = food[0][0];
const cookies = food[2][0];
const mangos = food[1][2]; // CHANGE ME
return { carrots, cookies }; // CHANGE ME
}
getFoodItems().mangos === "mangos";
true
.function getHistoricPrices(index) {
const bingo = index; // CHANGE ME
return bingo;
}
getHistoricPrices([true, false, true]);
true
.function getHistoricPrices(index) {
const bingo = index; // CHANGE ME
return bingo;
}
getHistoricPrices([
[true, false],
[false, true],
]);
true
.function getHistoricPrices(index) {
const bingo = index; // CHANGE ME
return bingo;
}
getHistoricPrices([
[
[true, false],
[true, false],
],
]);
true
.function getHistoricPrices(index) {
const bingo = index; // CHANGE ME
return bingo;
}
getHistoricPrices([[[{}, {}]]]);
Rest parameters allow us to collect an unknown number of arguments passed to a function into an array.
ES6 gives us more ways to handle parameters.
Default parameters:
function f(x, y = 7, z = 42) {
return x + y + z;
}
f(1); // 50
Rest parameter:
function f(x, y, ...a) {
return (x + y) * a.length;
}
f(1, 2, "hello", true, 7); // 9
restParams()
so that it returns true.function restParams(first, ...rest) {
return first === "first" && rest[0] === "second";
}
console.log(restParams(1)); // CHANGE ME
restParams2()
so that it returns true.function restParams2(first, ...rest) {
return first === "first" && rest[0] === "second" && rest[1] === "third";
}
console.log(restParams2(1)); // CHANGE ME
restParams3()
so that it returns true.function restParams3(first, ...rest) {
return (
first === "first" &&
rest[0] === "second" &&
rest[1] === "third" &&
rest[2] === undefined
);
}
console.log(restParams3()); // CHANGE ME
restParams4()
so that it returns true.function restParams4(...rest) {
return rest[2] === "first" && rest[0] === "second" && rest[1] === "third"; // CHANGE ME
}
console.log(restParams4("first", "second", "third"));
function restParams5(...rest) {
return rest; // CHANGE ME
}
restParams5(1, 2, 3, 4, 5, 6) === 6;
Math.max()
and spread operator to find the maximum number in both arrays.function findTheMax() {
const arr1 = [1, 7, 2, 4];
const arr2 = [1, 9, 5, 8];
return [arr1];
}
function concatenateArrays() {
const arr1 = [0, 1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
const result = // CHANGE ME
return result;
}
function mergeObjects() {
// what does this return?
const obj1 = {
a: "a from obj1",
b: "b from obj1",
c: "c from obj1",
d: {
e: "e from obj1",
f: "f from obj1",
},
};
const obj2 = {
b: "b from obj2",
c: "c from obj2",
d: {
g: "g from obj2",
h: "h from obj2",
},
};
const result = { ...obj1, ...obj2 };
return (
result.a === "YOUR_ANSWER" &&
result.b === "YOUR_ANSWER" &&
result.c === "YOUR_ANSWER" &&
result.d.e === "YOUR_ANSWER" &&
result.d.f === "YOUR_ANSWER" &&
result.d.g === "YOUR_ANSWER" &&
result.d.h === "YOUR_ANSWER"
);
}
ES6 introduced arrow functions, which allow us to write functions with shorter syntax.
To name an arrow function, you must save it as a variable. If the function has only one statement, and the statement returns a value, you can remove the brackets and the return keyword:
function getFive() {
return 5;
}
// Arrow function that has no parameter and returns value by default
const getFive = () => 5;
function divide(a, b) {
return a / b;
}
// Arrow function with parameters
const divide = (a, b) => a / b;
Multiple lines or expressions in an arrow function require the curly braces {}
and the keyword return
const squared = (x) => {
console.log(x);
return x * x;
}; // block
const squared = (x) => x * x; // expression
Summary
Arrow functions are handy for one-liners. They come in two flavors:
(...args) => expression
- the right side is an expression: the function evaluates it and returns the result.(...args) => { body }
- brackets allow us to write multiple statements inside the function, but we need an explicit return
to return something.x
function multiArgument() {
// CHANGE BELOW
const divide = function (a, b) {
return a / b;
};
return divide(40, 10);
}
function spreadWithArrow() {
// CHANGE BELOW
const asArray = function (...args) {
return args;
};
return asArray(1, 2, 3, 4);
}
function withObject() {
// CHANGE BELOW
const getObject = function (favoriteCandy) {
return { favoriteCandy };
};
return getObject("twix");
}
function withMultiLineExpression() {
// CHANGE BELOW
const getString = function (name) {
return `
Hello there ${name}
How are you doing today?
`;
};
return getString("Ryan");
}
function curryAdd() {
// CHANGE BELOW
return curryAddition(9)(3)(5);
function curryAddition(a) {
return function (b) {
return function (c) {
return a + b + c;
};
};
}
}
Rest parameters allow us to collect an unknown number of arguments passed to a function into an array.