These are a replacement for var
.
let
has block scoping and const
is immutable.
function testVar() {
var a = 30;
if (true) {
var a = 50;
console.log(a);
}
console.log(a);
}
testVar(); // 50 50
for (var i = 0; i < 5; i++) {
console.log(i); // 1, 2, 3, 4
}
console.log(i); // 5
function testLet() {
let a = 30;
if (true) {
let a = 50;
console.log(a);
}
console.log(a);
}
testLet(); // 50 30
for (let i = 0; i < 5; i++) {
console.log(i); // 1, 2, 3, 4
}
console.log(i); // undefined
It is not completely immutable. It only prevents the reassignment of a value to a constant, but it doesn't care about modifying the object.
const pi = 3.14;
pi = 42; // TypeError: Assignment to constant variable.
const person = {
name: "John"
};
person.name = "Mike";
console.log(person.name); // Mike. Doesn't prevent mutation.
class User {
// Called during instantiation.
constructor(username, email, password) {
(this.username = username),
(this.email = email),
(this.password = passwrod);
}
// Callable without instantiation.
static countUser() {
console.log("There are 50 users");
}
// Regular method.
register() {
console.log(this.username + " is registered.");
}
}
// Instantiation.
let bob = new User("Bob", "[email protected]", "1234");
bob.register(); // Bob is registered.
User.countUser(); // There are 50 users.
class Member extends User {
constructor(username, email, password, memberPackage) {
super(username, email, password); // Avoids doing this.username = username...
this.package = memberPackage; // Needs to be assigned since not in parent class.
}
getPackage() {
console.log(this.username + " uses the " + this.package + " package.");
}
}
let mike = new Member("Mike", "[email protected]", "1234", "standard");
mike.getPackage(); // Mike uses the standard package.
mike.register(); // Mike is registered.
Backticks allow multiline strings. Also, we can inject variables and functions with ${ var }
.
var name = "John";
var template =
"<h1>Hello, " + name + "</h1>" + "<p>This is a simple template.</p>";
let name = "John";
let template = `<h1>Hello, ${name}</h1>
<p>This is a simple template.</p>`;
let string = "Hello, I love Javascript.";
string.startsWith("Hello"); // true
string.endsWith("Javascript"); // false, since there is no dot.
string.includes("love"); // true
Number.isNaN("cat"); // true
Number.isInteger(1); // true
This is a collection of unique values. If we pass in an array with duplicates, we will get a collection (object) with unique values back. A weakSet
is a collection of unique objects only.
var array = [1, 2, 3, 3];
var set = new Set(array); // {1, 2, 3}
// Set methods
set.size; // 3
set.add("cat"); // [1, 2, 3, "cat"]
set.delete(2); // [1, 3, "cat"]
// Convert to array
var array = Array.from(set); // [1, 2, 3]
var array2 = [...set]; // [1, 2, 3]
function hello(name) {
return "Hello" + name;
}
console.log(hello("Jack")); // Hello Jack
// As long as no curly braces are used after the fat arrow, the return is implicit.
var hello = name => "Hello " + name;
console.log(hello("Jack")); // Hello Jack
They don't rebind this, they inherit it.
It provides a shorter syntax, and more importantly, it binds this
lexically, avoiding the usage of that
or self
. Arguments
and this
inside arrow functions reference their outer function.
Until arrow functions, every new function defined its own this
value. An arrow function does not have its own this
; the this
value of the enclosing execution context is used.
const obj = {
data: "John",
getData() {
console.log(this.data);
},
getData2: () => {
console.log(this.data);
}
};
obj.getData(); // John
obj.getData2(); // undefined
By not having a this
, they are best suited for non-method functions. Using them as methods results in undefined
.
// Old
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
that.age++; // this.age would refer to growUp, instead of Person.
}, 1000);
}
// New
function Person() {
this.age = 0;
setInterval(() => {
this.age++; // this refers to the Person object.
}, 1000);
}
let items = [1, 2, 3];
// Old
for (var i = 0; i < items.length; i++) {
console.log(array[i]);
}
// New
for (let item of items) {
console.log(item);
}
These are functions that can be paused and resumed. It can return i.e. yield values on each pause.
function* generateThreeNumbers() {
yield 1;
yield 2;
yield 3;
}
var numberIterator = generateThreeNumbers();
numberIterator.next(); // { value: 1, done: false }
numberIterator.next(); // { value: 2, done: false }
numberIterator.next(); // { value: 3, done: false }
numberIterator.next(); // { value: undefined, done: true }
another example...
function* generator() {
console.log("Hello");
yield "Yield 1 ran...";
console.log("World");
yield "Yield 2 ran...";
return "Done";
}
let gen = generator(); // Set the generator to a variable to extract data.
console.log(gen.next().value); // Hello, Yield 1 ran...
console.log(gen.next().value); // World, Yield 2 ran...
console.log(gen.next().value); // Done...
for (let g of gen) {
console.log(g); // Hello, Yield 1 ran, World, Yield 2 ran. Ignores last.
}
const address = {
street: "",
city: "",
country: ""
};
// old
const street = address.street;
const city = address.city;
const country = address.country;
// new
const { street, city, country: ctry } = address; // We can also rename the variables
// array
var foo = [1, 2, 3, 4];
var [one, two, three] = foo;
console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
// Default values. They work only if a property is undefined. null, false and 0 are all still values!
var obj = { a: 1 };
var { a, b = "something" } = obj;
console.log(a); // 1
console.log(b); // something
Electron example
// Old
const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
// New
const electron = require("electron");
const { app, BrowserWindow } = electron;
Used for copying or deleting properties from one object to another.
// Without spread
const meal = {
id: 1,
description: "Breakfast"
};
const updatedMeal = {
id: meal.id,
description: meal.description,
calories: 600
};
// With spread
const meal = {
id: 1,
description: "Breakfast"
};
const updatedMeal = {
...meal, // Injects the id and description properties from meal.
description: "Brunch", // This has precedence over the spread operator.
calories: 600
};
const meal = {
id: 1,
description: "Breakfast",
calories: 600
}
const = { id, ...mealWithoutId} = meal; // Destructuring.
console.log(mealWithoutId); // Object without the id property.
const first = [1, 2, 3];
const first = [4, 5, 6];
// old
const combined = first.concat(second);
// new
const combined = [...first, "a", ...second, "b"]; // Easy to add other items.
// Another example
const meals = [
{ id: 1, description: "Breakfast", calories: 420 },
{ id: 2, description: "Lunch", calories: 520 }
];
const meal = {
id: 3,
description: "Snack",
calories: 180
};
const updatedMeals = [...meals, meal]; // Returns a new array with the addition.