James Sherry PRO
Web Development Tutor and Co-Founder of { The Jump } Digital School
import - https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import
export - https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
// CommonJS export
module.exports = function(){
...
};
exports.data = [{..}, {..}];
exports.isDeveloper = false;
// CommonJS Import
var myProgram = require('./myJS');
var data = require('./myJS').data;
// ES6 export
export const MONTH = 'January';
export const DAY = 'Friday';
export default myFunc = function(){..};
// ES6 import
import passport from 'passport';
import myScript, { MONTH } from './myEs6';
const str = 'phil';
const str = 'dave'; // error - Can't redeclare
str = 'tom'; // error - Can't re-assign
const arr = [0,1,2];
arr.push(4); // works
const tutor = {
name: 'james'
};
tutor.name = 'rich'; // works
tutor = {
name: 'seymour'
}; // error - Can't re-assign
const is a constant which means that it cannot be re-declared or re-assigned
So, once assigned, an object can't be reassigned BUT its properties can be changed. (See here to stop that from happening)
let str = 'phil';
let str = 'dave'; // error - Can't redeclare
str = 'tom'; // works
let is a variable. It cannot be re-declared but it can be re-assigned.
let is like var but 'block scoped' (So not hoisted!)
function old(){
console.log(thing); // undefined
var thing = 'panda';
}
function new(){
console.log(thing); // ERROR
console.log(otherThing); // ERROR
let thing = 'panda';
const otherThing = 5;
}
You cannot access a let or const before it is defined - they are 'block scoped' not 'function scoped', so they are not hoisted.
// Multi params need ()s
(a, b) => {
return a + b;
}
// Single parameter
a => {
return a * 2;
}
// No params
() => {
return 'hello!';
}
// Implicit return
a => a * 2 // the product of a * 2 is implicitly returned
// Implicit return of an object
guest => ({ name: guest.name })
// Currying
let add = x => y => x + y;
//^^ Equivalent
let add = function (x) {
return function (y) {
return x + y;
};
};
function getThemeDetails(textColor = '#0f0', textSize = 16){
// ...
}
const name = 'phil';
const age = 24;
const sentence = `${name} is ${age} years old`;
const friends = [{name: 'tom', age: 27}, {name: 'geoff', age: 43}];
const sentence = `
<ul class="friends">
${friends.map(friend => `<li>${friend.name} is ${friend.age} years old</li>`).join('')}
</ul>
`;
You can execute javascript inside the ${} but it must be coerce-able into a string
You can manufacture HTML in the insertion points
const name = 'fido';
const age = 24;
const sentence = `${name} is ${ age * 7 } years old (in dog years)`;
Or you can use a function:
function createMarkup(){
let markup = ``;
if(....) {....} else {....}
return markup;
}
const sidebar = `<aside id="sidebar>${createMarkup()}</aside>`
const insurance_number = "JW735025B";
insurance_number.endsWith('B'); // true
insurance_number.endsWith('25', insurance_number.length - 1); // true
.startsWith(searchString[, startPosition]);
.endsWith(searchString[, length]);
const insurance_number = "JW735025B";
const international_insurance_number = "GBJW735025B";
let isNI_Number = insurance_number.startsWith('JW'); // true
let isNI_Number2 = international_insurance_number.startsWith('JW'); //false
let isINI_Number = international_insurance_number.startsWith('JW', 2); //true
.includes(searchString[, startPosition]);
'Blue Whale'.includes('blue'); // false Case sensitivity
'es6-es6-next'.includes('es6', 3); // true
.repeat(numberOfTimes);
'abc'.repeat(2); // 'abcabc'
(Position is optional, zero-based and defaults to 0)
const greeting = ' Hello world! ';
console.log(greeting);
// expected output: " Hello world! ";
console.log(greeting.trimEnd());
// expected output: " Hello world!";
.padStart/End(totalCharLength[, padding char]);
.trim[Start/End]();
const str1 = 'Breaded Mushrooms';
console.log(str1.padEnd(25, '.'));
// expected output: "Breaded Mushrooms........"
const str2 = '200';
console.log(str2.padEnd(5));
// expected output: "200 "
var person = {
name: 'James',
age: 39,
social: {
twitter: 'jmsherry',
facebook: 'panda.sherry'
},
};
// Old way
var name = person.name;
var age = person.age
// New way
const { name, age } = person; // Now 'name' and 'age' exist as variables
// Old way
const { twitter, facebook } = person.social; // as do 'facebook' and 'twitter'
// New way
const { name, social: { twitter, facebook } } = person;
var person = {
name: 'James',
age: 39,
social: {
twitter: 'jmsherry',
facebook: 'panda.sherry'
}
};
const { twitter:tw, facebook:fb } = person.social;
unpack into different variable names
format is originalName: newName
now 'fb' and 'tw' hold the twitter and facebook variables
var settings = {
width: 300,
height: 200,
};
const { width:w = '100%', height:h = '200', color = 'blue' } = settings;
w/ default arguments
format is value = default
const friends = ['tom', 'dave', 'hannah'];
const [friend1, friend2, friend3] = friends;
// Now friend1 is available as a variable and
// has the value 'tom'
//
// Is the equivalent of:
// const friend1 = friends[0];
const sports = 'basketball, baseball, football';
const [sport1, sport2, sport3] = sports.split(', ');
function announcePerson({name, rank}) {
console.log(`Introducing ${rank} ${name}`);
}
const person = {
rank: 'Lieutenant',
name: 'James Sherry',
};
announcePerson(person)
Which means they are found 'inside' each array you create
Create an array from any iterable thing (array, string, map, etc.)
const newArr = Array.from('foo');
console.log(newArr); // ["f", "o", "o"]
// OR
function adder(){
const numbers = Array.from(arguments);
const total = numbers.reduce((accumulator, currentValue) => accumulator + currentValue);
return total;
}
adder(1, 34, 98, 65, 23);
Array.isArray([1, 2, 3]); // true
Array.isArray({foo: 123}); // false
Array.isArray('foobar'); // false
Array.isArray(undefined); // false
Tests if something is an array (because typeof [] gives 'object')
Array(1,2,3); // [1,2,3];
Array(3); // [<empty slot>, <empty slot>, <empty slot>]
Array.of(3); //[3]
Because the Array() constructor has a fault
function getPerson(name, age){
return {
name: name,
age: age
};
}
// becomes
function getPerson(name, age){
return {
name,
age,
};
}
If the key matches the variable name then write it once
const VIP_SUFFIX = 'VIP';
const KEY = 'CLIENT';
const name = 'John'
let person = {}
person[`${KEY}-${VIP_SUFFIX}`] = name;
// or
person = {
[`${KEY}-${VIP_SUFFIX}`]: name;
}
Dynamically calculated things are often called: 'computed values'
function getPerson(name, age){
return{
start: function(){....},
stop: function(){....}
};
}
// becomes
function getPerson(name, age){
return{
start(){....},
stop(){....}
};
}
const firecrew = ['hannah', 'dave', 'kamarjit', 'paul', 'tom'];
const [CO, XO, ...crew] = firecrew;
// CO: hannah
// XO: dave
// crew: ['kamarjit', 'paul', 'tom']
The rest operator gathers things under one variable name
var arr1 = [0,1,2];
var arr2 = [3,4,5];
var arr3 = arr1.concat(arr2);
// becomes
const arr3 = [...arr1, ...arr2];
const arr4 = [...arr1, 'some other value', ...arr2];
fig. 1: An iterable
Let's think about other types of loop that we have:
const cuts = ['Middle', 'Back', 'Loin'];
for (const cut of cuts) {
console.log(cut);
}
// 'Middle', 'Back', 'Loin'
for (const [index, cut] of cuts.entries()) {
console.log(index, cut);
}
// 0, 'Middle', 1, 'Back', 2, 'Loin
//
const obj = { name: 'james', age: 43 };
for(const [key, value] of Object.entries(obj)) {
console.log(`key: ${key}, value: ${value}`);
}
const classroom = {
mary: {scores: [90, 70]},
john: {scores: [80, 60]},
mary: {scores: [85, 70]} // ERROR: Duplicate key
};
// vs
const classroom = {
[Symbol('mary')]: {scores: [90, 70]},
[Symbol('john')]: {scores: [80, 60]},
[Symbol('mary')]: {scores: [90, 70]} // No error
};
const COLOR_RED = 'Red';
const COLOR_ORANGE = 'Orange';
const COLOR_YELLOW = 'Yellow';
const COLOR_GREEN = 'Green';
const COLOR_BLUE = 'Blue';
const COLOR_VIOLET = 'Violet';
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_GREEN;
case COLOR_ORANGE:
return COLOR_BLUE;
case COLOR_YELLOW:
return COLOR_VIOLET;
case COLOR_GREEN:
return COLOR_RED;
case COLOR_BLUE:
return COLOR_ORANGE;
case COLOR_VIOLET:
return COLOR_YELLOW;
default:
throw new Exception('Unknown color: '+color);
}
}
// Prone to mix ups because of case and non-uniqueness. What if I have a:
const MOOD_BLUE = 'Blue';
// Better would be to use
const COLOR_RED = Symbol('Red');
const COLOR_ORANGE = Symbol('Orange');
const COLOR_YELLOW = Symbol('Yellow');
const COLOR_GREEN = Symbol('Green');
const COLOR_BLUE = Symbol('Blue');
const COLOR_VIOLET = Symbol('Violet');
See here for more
class Dog {} // hoisted
// or
const Dog = class {} // not hoisted
class Dog {
constructor(name, breed){ // required
this.name = name;
this.breed = breed;
}
// class method. Available on each object
speak(){
return `Bark! My name is ${this.name}!!`;
}
// static method. Available on class only
static getAgeinDogYears(age){
return age * 7;
}
set nickname(value) {
this.nick = value.trim();
}
get nickname() {
return this.nick;
}
}
function Dog(name, breed){
var _licenceNo = getLicenceNumber(); // private var
this.name = name; // public var
this.breed = breed
this.licenceNumber = function() { // privileged method
return _licenceNo;
}
}
Dog.prototype.speak = function(){ // public method
return `Bark! My name is ${this.name}!!`;
};
Dog.getAgeInDogYears = function(age){ // static method
return age * 7;
};
Dog.isDog = function(thing){....} // static
Note: No commas between methods ^^
class Animal {
constructor(name, noise){ // required
this.name = name;
this.thirst = 100;
this.belly = [];
this.noise = noise;
}
drink(){
this.thirst -= 10;
}
eat(item){
this.belly.push(item);
console.log(this.belly);
}
speak() {
return this.noise
}
}
class Dog extends Animal {
constructor(name, noise, breed){
super(name, noise);
this.breed = breed;
}
speak() {
return `${this.noise} - I am a dog!`;
}
fetch() {
console.log('Here\'s your stick back!');
}
}
const bear = new Animal('Boris', 'Grrr');
const fido = new Dog('Fido', 'Woof', 'spaniel');
Fido.fetch(); // Here's your stick back
Fido.eat('plastic');
bear.fetch(); // ERROR
bear.eat('dog'); // ['dog']
bear.speak(); // 'Grrr'
fido.speak(); // 'Woof I am a dog'
class Bike {
constructor(name) { this.name = name }
}
// Referenced from class (static)
Bike.shippingContainerType = 4;
// Every object gets a copy (public)
Bike.prototype.something = 25;
class MotorBike extends Bike {
licenceType = 1; // public
engine; // public
static getReg = function(){} //static
#privateThing = 2; // private
constructor(name, licenceType, priv){
super(name);
this.engine = {};
this.licenceType = licenceType;
this.privateThing = priv;
}
drive() {
return `I'm driving the ${this.name}`;
}
}
class MusicCollection extends Array {
constructor(title, ...tracks){
super(tracks);
this.title = title;
}
add(track){
this.push(track);
}
}
const musicCollection = new MusicCollection('James\'s Music', {
band: 'Drowning Pool',
track: 'Bodies'
}, {
band: 'Machine Head',
track: 'Davidian'
}, {
band: 'Filter & Crystal Method',
track: 'Trip Like I Do'
}, {
band: 'Devin Townsend Project',
track: 'The Death of Music'
});
const myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
const iterator = myIterable[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
console.log([...myIterable]); // [1, 2, 3]
for (const item of myIterable) {
console.log("item", item);
}
function* myGenerator(name){
yield 'James';
yield 'Sherry';
}
const iterator = myGenerator();
iterator.next(); // {value: 'James', done: false}
iterator.next(); // {value: 'Sherry', done: false}
iterator.next(); // {value: undefined, done: true}
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception
const colourArray = ['red', 'red', 'orange', 'blue'];
const colourSet = new Set(colourArray);
console.log(colourArray); // ['red', 'red', 'orange', 'blue']
console.log(colourSet); // ['red', 'orange', 'blue']
const colourSet = new Set(['red', 'orange', 'blue']);
colourSet.add('pink');
console.log(colourSet); // ['red', 'orange', 'blue', 'pink']
colourSet.has('pink'); // true
colourSet.delete('pink'); // true
console.log(colourSet) // ['red', 'orange', 'blue']
colourSet.clear(); // true
console.log(colourSet) // Set(0) {}
...get you an iterator (See generator functions) to use with for...of loops
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window); // true
ws.has(foo); // false, foo has not been added to the set
ws.delete(window); // removes window from the set
ws.has(window); // false, window has been removed
If you answer 'yes' to any of the following questions:
const myMap = new Map();
myMap.set(2, 'pink');
console.log(myMap); // Map(1) {2 => "pink"}
console.log(myMap.has(2)); // true
myMap.delete('bar'); // True if found and removed; false if not
var myMap = new Map();
myMap.clear();
console.log(myMap); // Map(0){}
console.log(myMap.get(2)); // 'pink'
console.log(myMap.size); // 1
myMap.forEach(function logMapElements(value, key, map) {
console.log(`m[${key}] = ${value}`);
});
.entries(), .keys(), .values() get you an iterator
const clickCount = new WeakMap();
let btns = document.getElementsByTagName('button');
btns.forEach((btn) => {
clickCount.set(btn, 0);
btn.addEventListener('click', (e) => {
const count = clickCount.get(e.target);
clickCount.set(e.target, count+=1);
});
});
Skip until ajax
var isMomHappy = false;
// Promise
var willIGetNewPhone = new Promise(
function (resolve, reject) {
if (isMomHappy) {
var phone = {
brand: 'Samsung',
color: 'black'
};
resolve(phone); // fulfilled
} else {
var reason = new Error('mom is not happy');
reject(reason); // reject
}
}
);
//Format: var myPromise = new Promise(executor);
var askMom = function () {
console.log('start');
willIGetNewPhone
.then(function (fulfilled) {
// yay, you got a new phone
console.log('middle', fulfilled);
// output: { brand: 'Samsung', color: 'black' }
})
.catch(function (error) {
// oops, mom don't buy it
console.log(error.message);
// output: 'mom is not happy'
});
console.log('end');
};
askMom();
/* You'll get: start, end, middle {result}
/* ES7 */
const isMomHappy = true;
// Promise
const willIGetNewPhone = new Promise(
(resolve, reject) => {
if (isMomHappy) {
const phone = {
brand: 'Samsung',
color: 'black'
};
resolve(phone);
} else {
const reason = new Error('mom is not happy');
reject(reason);
}
}
);
// 2nd promise
async function showOff(phone) {
return new Promise(
(resolve, reject) => {
const message = 'Hey friend, I have a new ' +
phone.color + ' ' + phone.brand + ' phone';
resolve(message);
}
);
};
// call our promise
async function askMom() {
try {
console.log('before asking Mom');
const phone = await willIGetNewPhone;
const message = await showOff(phone);
console.log(message);
console.log('after asking mom');
}
catch (error) {
console.log(error.message);
}
}
(async () => {
await askMom();
})();
optional chaining, nullish coalescence, BigInt
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog.name; // Throws: "Cannot read properties of undefined (reading 'name')"
const value = adventurer.someNonExistentMethod(); // Throws: "adventurer.someNonExistentMethod is not a function"
const dogName = adventurer?.dog?.name;
console.log(dogName);
// expected output: undefined
console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined
// if undefinedValue is undefined, result: 'some other default'
const undefinedValue = response.settings.undefinedValue ?? 'some other default';
// if nullValue is null, result: 'some other default'
const nullValue = response.settings.nullValue ?? 'some other default';
// result: '': This would default with || because '' is falsey
const headerText = response.settings.headerText ?? 'Hello, world!';
// result: 0: This would default with || because 0 is falsey
const animationDuration = response.settings.animationDuration ?? 300;
// result: : This would default with || because false is falsey
const showSplashScreen = response.settings.showSplashScreen ?? true;
By James Sherry
Intro to ES6/7