Notes for CodeSchool's ES2015

* this is a repost from *

The following are my notes for ES2015: The Shape of JavaScript to Come course: . The course gives an overview of the new syntax features available in ES2015. (Please also see the attached file for better formatting.)

ES2015: The Shape of JavaScript to Come

ES2015 new features in javascript

new variable and function declarations
more efficient data structures
promises and generators

* notes 1.1


because of hoisting var declarations are moved to the top of scope, making variables visible to entire function

let keyword defines variables assigned to block not fuction

* challenge 1.2

function loadProfiles(userNames){
let message = "Loading " + userNames.length + " user(s)";


_fetchProfiles(userNames, function(data){
let profiles = data.profiles;

* challenge 1.3

Using let instead of var prevents variable declarations from being moved to the top of the scope on what is known as: hoisting

* notes 1.4


using var in loops can cause problems during callbacks since the var is hoisted before callback functions

if let is used in the for loop the problem is solved because it is not hoisted

let variables can be reassigned, but they cannot be redeclared without throwing an error

* challenge 1.5

function getUsersAvatars(userNames, cb){
let url = "/userAvatars/";

for(let index in userNames){
_fetchAvatar(endpoint + userNames[index], function(avatarUrl){
_displayAvatar(userNames[index], avatarUrl);

* challenge 1.6

What is the outcome of the following code?

let name = "Jerry Only";
name = "Glenn Danzig";
console.log( name );

Glenn Danzig

* challenge 1.7

What is the outcome of the following code?

let topic = "The latest news in JavaScript";
let topic = "The latest news in ES2015";
console.log( topic );

The code generates a TypeError

* challenge 1.8

let message = "web forum";

function printInCaps(value){
let message = value.toUpperCase();
return message;


console.log( message );

The code prints the following to the console: web forum

* notes 1.9


when numbers are used in comparisons, it makes code hard to read

CONST can be used to create a read-only value
constants can not be reassigned
const must be assigned a value on declaration
const are not hoisted

let should be used over const when values could change

* challenge 1.10

function validateMessage(author, message){
if(message.length > MAX_MESSAGE_LENGTH){
message = _trimMessage(message);
_postMessage(author, message);

* challenge 1.11

function loadProfiles(userNames){
const MAX_USERS = 15;
if(userNames.length > MAX_USERS){
return false;
for(let i=0; i < userNames.length; i++){
_fetchProfile(userNames[i], function(data){
_addToSidebar(userNames[i], data);

* challenge 1.12

What will the following code output?

function hideReplies(topicId){
let previewText;
const TEXT_SEPARATOR = '%%';
previewText = _fetchLongPreview(topicId, TEXT_SEPARATOR);
previewText = _fetchPreview(topicId);
console.log( TEXT_SEPARATOR );


* challenge 1.13

function reportAbuse(topicId, throttler){
if(throttler.recentAbuseReports > MAX_REPORTS_PER_MINUTE){
return false;
_reportTopic(topicId, function(topic){
let message = "Topic " +;
message += " reported.";
message += " encountered an error!";

* notes 2.1


functions can use defaults in argument declarations - this is a default parameter
function myFunc(arg=[]) {…}

option objects are often used to pass extra arguments to an object, but it is hard to know what those options are
function myFunc(arg1, options = {}) {…}
these parameters can be named -> named parameters
function myFunc(arg1, {arg2, arg3} = {}) {…}
named parameters can be used directly in code

challenge 2.2

function displayTopicsPreview( topics = [] ){
let message = "There are currently " + topics.length;
_displayPreviewMessage(topics, message);

challenge 2.3

function setPageThread(name, {popular, expires, activeClass} ){
let nameElement = _buildNameElement(name);
let settings = _parseSettings(popular, expires, activeClass);
_updateThreadElement(nameElement, settings);

challenge 2.4

function loadProfiles(userNames = [], {profilesClass, reverseSort} = {}) {
profilesClass = profilesClass || ".user-profile";
reverseSort = reverseSort || false;
if (reverseSort) {
userNames = _reverse(userNames);
_loadProfilesToSideBar(userNames, profilesClass);

* challenge 2.5

Take the following function:
function fetchReplies(topicId, { displayClass, includeAvatar }){
Mark all the possible ways this function can be invoked without generating an error.

fetchReplies(12, {displayClass: "topic-replies"});

let options = {displayClass: "topic-replies", includeAvatar: true};
fetchReplies(12, options);

* challenge 2.6

Take the following function, which sets a default value for the second parameter:

function setPageThread(name, {popular, expires, activeClass} = {}){
// ...
Mark all the possible ways this function can be invoked without generating an error.

setPageThread(“ES2015”, {popular: true});

setPageThread(“ES2015”, {});


* notes 2.7


variadic functions can take any number of arguments
previously you would use a for loop on the argument array
this way the argument was unclear ; changing any arguments breaks it

rest parameters change any number of parameters into an array
function thisFunc( …tags) {};
rest parameters have to be last in function
rest parameter is used in function definitions

the spread operator allows for an array to broken into individual items for a function call
the spread operator is used in function invocations

arrow functions have lexical binding and bind to the scope where they are defined (not where used)
this helps with problem where anon callback functions cannot use variables in parent scope

* challenge 2.8

function appendUserNames( ...userNames ){
let userNameDivs = "";
let USER_CLASS = ".forum-user";
for(let i in userNames){
let name = userNames[i];
if(name !== "admin"){
userNameDivs += "" + name + "";
return userNameDivs;

* challenge 2.9

getActiveUsers(15, function(data){
let userNameDivs = appendUserNames( );
appendToSidebar(".side-bar", userNameDivs);
function getActiveUsers(topicId, cb){
_fetchTopicInfo("/topics/" + id, function(data){

* challenge 2.10

See the function below:
let printName = function(value){
console.log( value );
How could we write its arrow function counterpart?

let printName = (value) => {
console.log( value );

* notes 3.1


Object initializer shorthand => from variables to object properties
when an object is being created and properties have same name as assigned variable

let name = "Sam";
let age = 45;
let user = {name, age}; => same as let user = {name:name, age:age};

Object destructuring => from object properties to variables
to assign properties from an object to local variables with same name

let { name, age } = buildUser("sam", 45);

only a subset of properties can be asked for

Method Initializer shorthand
the keyword function is no longer needed when adding a method to an object

return ….

Template Strings
a string literal with embedded expressions wrapped in ${}

let user = `His name is ${name} and he is ${age} years old.`

allows for multiline text

* challenge 3.2

let name = "Brook";
let totalReplies = 249;
let avatar = "/users/avatars/brook-user-1.jpg";
let user = {name, totalReplies, avatar};

* challenge 3.3

function buildTopicElement(topic){
let title = "

" + topic.title + "

let author = "" + + "";
let body = "

" + topic.body + "

return { title, author, body };

* challenge 3.4

let {fullName} = buildUser("Tyler", "Williams");
let title = "The New Object Syntax - Good or Bad?";
let author = fullName;
let body = "What do you all think of the new syntax? I like it!";
let topic = { title, author, body };
let element = buildTopicElement(topic);

* challenge 3.5

The new object initializer shorthand and object destructuring look very similar, but they are used in different scenarios. Identify which syntax is being used in the code snippets below:

// Snippet #1
let { tags, isLocked } = topicInfo(17);

// Snippet #2
let reply = { author, body, repliedAt };

// Snippet #3
function buildMetadata(object){
let id = parseInt(;
let lastUpdatedAt = object.updatedAt || object.createdAt;
let hashCode = _buildHashCode(object);
return { id, lastUpdateAt, hashCode };

Destructuring, Initializer, Initializer

* challenge 3.6

function buildMetadata(object){
let id = parseInt(;
let lastUpdatedAt = object.updatedAt || object.createdAt;
let hashCode = _buildHashCode(object);
return {
isSecureHash() {
return hashCode >= SECURE_HASH_CODE_LENGTH;

* challenge 3.7

let replyCount = 21;
let message = `This topic has a total of ${replyCount} replies`;

* challenge 3.8

function buildTopicElement(topic){
let title = `


let author = ` ${} `;
let body = `


return { title, author, body };

* notes 3.9


object.assign(object to modify, object, object, …)

this is a variadic function and can take multiple objects
all properties are added to first object, if duplicates the last one is taken

this works very well to pass an option parameter into a function and merge with a defaults object to get a new settings object

it is often good to pass an empty object into the first parameter and used the returned object

* challenge 3.10

Given the following objects:
let defaults = {
container: ".main",
isActiveClass: ".is-active"
let options1 = {
container: ".main-container",
isActiveClass: ".is-active-element"
let options2 = {
isActiveClass: ".is-active-content"
What will be the resulting object assigned to the settings variable when we merge them using Object.assign, like so:
let settings = Object.assign({}, defaults, options1, options2);

{ container: '.main-container', isActiveClass: '.is-active-content' }

* challenge 3.11

function spinner(target, options = {}){

let defaults = {
message: "Please wait",
spinningSpeed: 5,
cssClass: ".is-spinning"

let settings = Object.assign({}, defaults, options);

if(settings.spinningSpeed !== defaults.spinningSpeed){
settings.cssClass = _addSpeedClass(target);

_renderSpinner(target, settings);

* challenge 3.12

Given the spinner() function below:
function spinner(target, options = {}) {
let defaults = {
message: "Please wait",
spinningSpeed: 5,
cssClass: ".is-spinning"
let settings = Object.assign({} , defaults , options);
console.log(`Message: ${settings.message}`);
console.log(`spinningSpeed: ${settings.spinningSpeed}`);
console.log(`cssClass: ${settings.cssClass}`);
Indicate the outcome of invoking this function, like so:
spinner(targetElement, {
cssClass: ".is-fast-spinning",
spinningSpeed: 8

Message: Please wait
spinningSpeed: 8
cssClass: .is-fast-spinning

* notes 4.1


array destructuring
let users = ["sam", "tom", "sally"];
let [a, b] = users;

can assign multiple from an array to local variables
values can be skipped
let [a,,c] = users;
works great with rest parameters
let [a, …rest] = users;
when returning arrays from functions multiple values can be assigned at once

for … of loops
loops through arrays and gets value
for(let name of names) {console.log(name);}
cannot be used on plain objects
we can check if an object can be used with forof by checking for Symbol.iterator

returns the first element in the array that satisfies a test function

* challenge 4.2

Which of the following uses the correct syntax for array destructuring?

let [a, b, c] = ["Programming", "Web", "JavaScript"];

* challenge 4.3

let [first, ...remainingUsers] = ["Sam", "Tyler", "Brook"];
addActiveUsers(first, remainingUsers);

* challenge 4.4

function buildTopicInfo(topic){
let title = `


let author = `${}`;
return [title, author];
let topic = getCurrentTopic();
let [topicTitle, topicAuthor] = buildTopicInfo(topic);

* challenge 4.5

let topicId = currentTopic();
let activeUsers = ["Sam", "Tyler", "Brook"];
for( let name of activeUsers ){
notifyTopicReply(topicId, name );

* challenge 4.6

What is the outcome of running the following code?

let topicInfo = {
title: "New Features in JS",
replies: 19,
lastReplyFrom: "Tyler"
for(let [k, v] of topicInfo){
console.log(`${k} - ${v}`);

A TypeError

* challenge 4.7

Given the following array:

let recentTopics = [
title: "Semi-colons: Good or Bad?",
isLocked: true
title: "New JavaScript Framework Released",
isLocked: true
title: "ES2015 - The Shape of JavaScript to Come",
isLocked: false
Which of the following options will return the first topic object that is not locked? Check all that apply.

recentTopics.find( topic => !topic.isLocked );
recentTopics.find( (topic) => !topic.isLocked );

* notes 4.8


maps are a data structure of key value pairs
each key only has one value
maps are better than objects because object keys are always strings
maps can be iterated over in forof loops
to add entries use set(key, value) method
let totalReplies = new Map();
totalReplies.set( user1, 5 );
to read a value from a map we use get(key)
console.log( totalReplies.get( user1 ) );

maps should be used when keys are unknown until runtime
objects should be used if keys are predefined
maps should use the same types for all keys and all values
otherwise objects are good

in weakmaps only objects can be used as keys
let mapSettings = new WeakMap();
no primitive datatypes can be used
all methods use an abject as a key
weakmaps are not iterable

individual entries are available for cleanup inside a weakmap
which is better for memory

* challenge 4.9

In the Map data structure, each key is associated with one value.

* challenge 4.10

Given this initial code:

let author1 = { name: "Sam" };
let author2 = { name: "Tyler" };
let mostRecentReply = {};
mostRecentReply[author1] = "ES2015";
mostRecentReply[author2] = "Semi-colons: Good or Bad?";

What will be the output of the following code?

console.log( mostRecentReply[author1] );
console.log( mostRecentReply[author2] );

Semi-colons: Good or Bad?
Semi-colons: Good or Bad?

* challenge 4.11

The Map object is a simple key/value data structure. We use the set method to add entries, and the get method to read entries.

* challenge 4.12

let author1 = { name: "Sam" };
let author2 = { name: "Tyler" };
let totalReplies = new Map();
console.log( `Total Replies: ${totalReplies.get(author1)}` );
console.log( `Total Replies: ${totalReplies.get(author2)}` );

* challenge 4.13

In the code below, we are not using the most appropriate data structure. What’s wrong with this code?

let recentPosts = {};

getPost(postId, (data) => {
recentPosts[] = data.title;

recentPosts should be a Map, since keys are unknown until runtime.

* challenge 4.14

In the code below, is it appropriate to use a JavaScript object as a map?

const USERS_PER_PAGE = 10;

let pageSettings = {
canSort: false

Yes. Since keys like perPage and canSort are previously defined, we don't run the risk of accidentally overwriting values.

* challenge 4.15

let recentPosts = new Map();
recentPosts.set( "Sam", "ES2015" );
recentPosts.set( "Tyler", "CoffeeScript" );
recentPosts.set( "Brook", "TypeScript" );
for(let [user, postTitle] of recentPosts ){
console.log(`${user} = ${postTitle}`);

* challenge 4.16

The WeakMap is a more memory efficient type of Map where only objects can be passed as keys. Primitive data types such as strings, numbers, booleans, etc. are not allowed.

* notes 4.17


in arrays duplicate entries are allowed
sets store unique values of any type

let tags = new Set();

sets are iterable and can be destructured and used with for…of


a type of set where only objects can be stored
allows for garbage collection

let weakTags new WeakSet();
let iOS = {name:"iOS"};

weaksets can not be used in forof
they offer no methods for reading values

WeakSets work good to prevent mutating other objects
by adding an immutable object to a weakset, then testing for presence

* challenge 4.18

Which of the following describes a limitation of Arrays?

Arrays don't enforce uniqueness of items. Duplicate entries are allowed.

* challenge 4.19

let tags = new Set();
console.log(`Total items ${tags.size}`);

* challenge 4.20

let tags = new Set();
for( let tag of tags ){
console.log(`Tag: ${tag}`);

* challenge 4.21

let tags = new Set();
let [first] = tags;
console.log( `First tag: ${first}` );

* challenge 4.22

The WeakSet is a more memory efficient type of Set where only objects are allowed to be stored.

* challenge 4.23

Given the following code:

let allPosts = new WeakSet();
let post1 = { title: "ES2015" };
let post2 = { title: "CoffeeScript" };
let post3 = { title: "TypeScript" };
allPosts.add( post1 );
allPosts.add( post2 );
allPosts.add( post3 );

How can we query the allPosts WeakSet to determine whether it has the post2 object?

allPosts.has( post2 );

* notes 5.1


allows for object oriented syntax code

class NameOfClass {
constructor(name) { = name;
// …

the constructor method is run when a new instance is created with new operator
instance variables created in constructor are available to instance methods

there are no private methods in javascript
but prefixing a method with an underscore is a convention

class syntax is not adding a new data model to javascript

classes can use inheritence

class SecondClass extends NameOfClass {
constructor(something) {

the keyword extends causes a class to inherit properties and methods from a parent class

the super() method must be called first in the child constructor
this runs parents constructor code

super is an object that points back to parent class

* challenge 5.2

When writing JavaScript classes, there's a special method for creating and initializing an object. This method is called the constructor method.

* challenge 5.3

class TopicReplyCounter {
constructor(topicId, replies){
this.topicId = topicId;
this.replies = replies || [];
this.replyCount = this.replies.length;
this.replyCount = this.totalReplies().length;
return this.replies.filter( reply => !reply.isAbuse );
return this.replyCount;

* challenge 5.4

class TagManager {
constructor(topicId) {
this.topicId = topicId;
addTag(tagName) {
API.createTag(tagName, this.topicId);
removeTag(tagName) {
API.deleteTag(tagName, this.topicId);

* challenge 5.5

class SidebarAdvertisement extends Advertisement {
constructor(title, link) {
super(title, link);
_linkText() {
return("Sign up now!");

* challenge 5.6

In the code below, we have a parent class ShoppingCart and a child class ForumShoppingCart.

class ShoppingCart {
this.userId = userId;
this.products = [];
//... complex math
class ForumShoppingCart extends ShoppingCart {
let partialCost = // call parent class `calculate` method here
return partialCost - _calculateDiscount();
//... complex math

From the ForumShoppingCart class, how can we invoke the calculate method from its parent class, ShoppingCart?


* notes 5.7


commonly to modularize code we use global variables
which could lead to naming conflicts

to create a module

export default function(message){
} => in flash-messsage.js

import flashMessage from './flash-message';
flashMessage("Hello"); => in app.js

both files are added to html page

this prevents pollution of global namespace

the default export does not allow for multiple exported functions

Named Exports

to export multiple functions
all functions must be named
do not use default keyword

export function alertM(message){…}
export function logM(message){…} => in flash-messsage.js

import {alertM, logM} from './flash-message';
flashM("Hello"); => in app.js

names must be exactly the same for the functions

Importing the entire module as an object
then you can call the functions as property

import * as flash from './flash-message';

the export keyword can also be removed from functions and be used independently
export { alertM, logM }

* challenge 5.8

Indicate the biggest benefit of using the JavaScript module system.

Avoid polluting the global namespace.

* challenge 5.9

export default function isTopicValid(topic){
const MAX_TITLE_LENGTH = 20;
let isValid = !(topic.title.length > MAX_TITLE_LENGTH ||;
return isValid;

* challenge 5.10

import isTopicValid from './is-topic-valid.js';
let topic = {
title: "ES2015",
author: { name: "Sam", isBlocked: false }

* challenge 5.11

function isTopicValid(topic){
const MAX_TITLE_LENGTH = 20;
let isValid = !(topic.title.length > MAX_TITLE_LENGTH ||;
return isValid;
function isEmailAuthorized(email){
const EMAIL_DOMAIN = "";
return email.indexOf(EMAIL_DOMAIN) > 0;
export { isTopicValid , isEmailAuthorized };

* challenge 5.12

import { isTopicValid , isEmailAuthorized } from './validators';
let author = { name: "Sam", email: "", isBlocked: false };
let topic = {
title: "ES2015",

* notes 5.13

using modules to encapsulate const in classes

const are limited to scope and are often repeated (i.e. MAX_USERS)

const can be encapsulated within their own module
this allows them to be used by oth modules

in constants.js
export const MAX_USERS = 3;
export const MAX_REPS = 3;

in apps.js
import { MAX_USERS, MAX_REPS } from './constants.js';

classes can also be exported from modules

in flash-message.js
export default class FlashM {
in apps.js
import FlashM from 'flash-message.js';
let flash = new FlashM("hello");

using default export allows us to name it anything on export

can also be exported as a named export

class Flashm {…}
export { FlashM }

import { FlashM } from 'flash-message.js';

* challenge 5.14

const MAX_TITLE_LENGTH = 20;
const EMAIL_DOMAIN = "";

* challenge 5.15

export default class TagManager {
this.topicId = topicId;
API.createTag(tagName, this.topicId);
API.deleteTag(tagName, this.topicId);

* challenge 5.16

import TagManager from './tag-manager-class';
let tagManager = new TagManager(20);

* challenge 5.17

import { Advertisement } from "./advertisement-class";
class SidebarAdvertisement extends Advertisement {
constructor(title, link){
super(title, link);
return "Sign up now!";
export { SidebarAdvertisement };

* notes 6.1


Javascript is a single thread model.
Blocking the page can be done when waiting for synchronous requests

CPS is continuation-passing style
tell a function how to continue execution by passing a callback
code can get extremely nested and complicated

a promise is an abstraction that allows us to write async code

creating a new promise object
a promise constructor function take two callback arguments call handlers
resolve - called when the non-blocking code is done executing
reject - called when errors occur

promises have a lifecycle
it starts at pending
then goes to fulfilled or rejected

a promise represents a future value

calling the resolve function moves the promise to a fulfilled state

then() method reads results when a promise is fullfilled
then() method takes a function that is invoked when the the promise is resolved
multiple then methods can be chained together

reject handler
gets an error object

catch method is called with an error

* challenge 6.2

Creating a new Promise automatically sets it to the pending state. Then, it can move to 1 of these 2 states: the fulfilled state if the resolve() handler is called, or the rejected state if the reject() handler is called.

* challenge 6.3

export default function getReplies(topicId){
return new Promise(function( resolve , reject ){
_getRepliesForTopic(topicId, function(data){
let replies = data.replies;
let error = new Error("An error occurred");

* challenge 6.4

return replies.filter( reply => !reply.isAbuse );
console.log( filteredReplies );

* notes 6.5


iterable - arrays are iterable and we can use with for of
objects are not iterable

iterables return an iterator object and can keep track of position while accessing items one at a time
they are stepped through by using next() function
returns an object with propertied done and value

objects can be made to be iterable by creating a function returned by Symbol.iterator method
a next method needs to defined to return an object with done and value

objects that iterable
can be spread or deconstructed

* challenge 6.6

Iterables return an object called an iterator. This object knows how to access items from a collection 1 at a time, while keeping track of its current position within the sequence.

* challenge 6.7

An iterator object has a method called next(). Each time next() is called, it returns an object with 2 specific properties. These are:

done and value

* challenge 6.8

let user = {
name: "sam", totalReplies: 17, isBlocked: false
user[Symbol.iterator] = function(){
let properties = Object.keys(this);
let count = 0;
let isDone = false;
let next = () => {
if(count >= properties.length){
isDone = true;
let value = this[properties[count++]];
return { done: isDone , value } ;
return { next };

* notes 6.9


a generator function is declared with a * following the function keyword
uses the yield keyword to return iterable values
returns an object that provides a next method
can be used in spread and destructuring

can be used to shorten iterator functions on objects

* challenge 6.10

Generator functions are special functions from which we can use the yield keyword to return iterator objects.

* challenge 6.11

function *topicList(){
yield "ES2015";
yield "Semi-colons: good or bad?";
yield "TypeScript";
for( let topic of topicList() ){
console.log( topic );

* challenge 6.12

Check all other valid ways we can use our topicList() generator function.

function *topicList(){
yield "ES2015";
yield "Semi-colons: good or bad?";
yield "TypeScript";

let names = [...topicList()];
console.log( names );

let [first,] = topicList();
console.log( first, rest );

* challenge 6.13

let user = {
name: "sam", totalReplies: 17, isBlocked: false
user[Symbol.iterator] = function * (){
let properties = Object.keys(this);
let count = 0;
let isDone = false;
for(let p of properties){
yield this[p];
for(let p of user){
console.log( p );