Becoming Better at

JavaScript

MUG040

new Date(2017, 10, 22);

JavaScript is coming
for you

Gaya Kessler

Freelance Full Stack Web Developer

JavaScript, React, Node.js


Creator of Drammit and Formable

@GayaKessler on Twitter

Frontend is
moving fast

"That is so last week!"

It's hard to start learning or improving skills

When all that's written is already outdated

So what should I do?

Talk outline

1. Understanding the fundamentals

2. Moving forward

3. Beyond the browser

1. The fundamentals

Scopes and Closures

Closures


function nameGenerator() {
	var name = 'Gaya';

	function giveName() {
		return name;
	}

	return giveName;
}

var generate = nameGenerator(); // puts giveName() in generate

generate(); // Gaya

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000);
}

// 5
// 5
// 5
// 5
// 5

Closures


for (var i = 0; i < 5; i++) { // <-- create scope for 'i'
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000);
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000); // <-- 0 * 1000
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000); // <-- 1 * 1000
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000); // <-- 2 * 1000
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000); // <-- 3 * 1000
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000); // <-- 4 * 1000
}

Closures


for (var i = 0; i < 5; i++) { // <-- i++ = 5
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000);
}

Closures


for (var i = 0; i < 5; i++) {
	setTimeout(function timer() {
		console.log(i); // 5
	}, i * 1000);
}

Closures to the rescue!


for (var i = 0; i < 5; i++) {
	(function (j) {
		setTimeout(function timer() {
			console.log(j);
		}, j * 1000);
	})(i);
}

Closures to the rescue!


function createTimer(j) {
	return function timer() {
		console.log(j);
	}
}

for (var i = 0; i < 5; i++) {
	setTimeout(createTimer(i), i * 1000);
}

What is this?


function foo(cb) {
	this.a = 'hey';
	cb();
}

function bar() {
	console.log(this.a);
}

var hi = bar;
hi.a = 'hi';

foo(hi); // hey
hi.a; // hi

function foo(cb) { // <-- `bar` is `cb`
	this.a = 'hey';
	cb(); // <-- call site
}

function bar() {
	console.log(this.a); // <-- now `this` is `foo`
}

var hi = bar;
hi.a = 'hi';

foo(hi);
hi.a;

function foo(cb) {
	this.a = 'hey';
	cb(); // <-- still the same call site
}

function bar() {
	console.log(this.a); // <-- but `this` is bound to `hi`
}

var hi = bar;
hi.a = 'hi';

foo(hi.bind(hi)); // hi

this or that


var Gaya = {
	hobby: 'Whisky',
	sayHobby: function () {
		console.log(this.hobby);
	},
	sayHobbyAfterAFewDrinks: function () {
		setTimeout(function () {
			console.log(this.hobby);
		}, 1000);
	},
};

Gaya.sayHobby(); // Whisky
Gaya.sayHobbyAfterAFewDrinks(); // undefined

this or that


var Gaya = {
	hobby: 'Whisky',
	sayHobby: function () {
		console.log(this.hobby);
	},
	sayHobbyAfterAFewDrinks: function () {
		var that = this;
		setTimeout(function () {
			console.log(that.hobby);
		}, 1000);
	},
};

Gaya.sayHobby(); // Whisky
Gaya.sayHobbyAfterAFewDrinks(); // Whisky

this or that


var Gaya = {
	hobby: 'Whisky',
	sayHobby: function () {
		console.log(this.hobby);
	},
	sayHobbyAfterAFewDrinks: function () {
		setTimeout(function () {
			console.log(this.hobby);
		}.bind(this), 1000);
	},
};

Gaya.sayHobby(); // Whisky
Gaya.sayHobbyAfterAFewDrinks(); // Whisky

this or that


var Gaya = {
	hobby: 'Whisky',
	sayHobby: function () {
		console.log(this.hobby);
	},
	sayHobbyAfterAFewDrinks: function () {
		setTimeout(() => {
			console.log(this.hobby);
		}, 1000);
	},
};

Gaya.sayHobby(); // Whisky
Gaya.sayHobbyAfterAFewDrinks(); // Whisky

Object context


var Car = {
	sound: 'Vroom vroom',
	drive: function () {
		console.log(this.sound);
	}
};

var Bus = {
	sound: 'Rumble rumble',
	drive: Car.drive,
};

Bus.drive(); // Rumble rumble

Async

Callbacks


function superHardMathProblem(callback) {
	console.log('Thinking...');

	setTimeout(callback, 1000);
}

superHardMathProblem(function () {
	console.log('Done!');
});

// do other stuff

Callbacks are used heavily in Node.js

Error first style callbacks

Callback hell


setTimeout(function() {
  setTimeout(function() {
	setTimeout(function() {
    	setTimeout(function() {}, 100);
  	}, 100);
  }, 100);
}, 100);

Still callback hell


function wait(cb) {
	setTimeout(cb, 100);
}

wait(wait(wait(function () {
	console.log('Waited for 300ms!');
})));

Still callback hell


function step1() {
	setTimeout(step2, 100);
}

function step2() {
	setTimeout(step3, 100);
}

function step3() {
	console.log('I am done!');
}

step1();

Promises


var step1 = () =>
	new Promise(resolve => setTimeout(resolve, 100));

var step2 = new Promise(function (resolve) {
	setTimeout(resolve, 100);
});

var step3 = new Promise(function () {
	return 'I am done!';
});

step1().then(step2).then(step3)
	.then(console.log).catch(console.error); // I am done!

Promises are future values

Promises are always async

Promise.all()

Promise.race()

Promise.resolve()

Object Oriented programming in JavaScript

"Composition over inheritance."

- Design Patterns by Gang of Four (1994)

How we explain inheritance

But what if we want a mammal which lays eggs?

Classes in JavaScript

A complete and utter mess

The pre ES6 way


function StrangeThing() {
	// ... some constructor
}

StrangeThing.prototype.upsideDown = function () {
	// ... some action
}

console.log(StrangeThing);
	// function StrangeThing()

var instance = new StrangeThing();
console.log(instance);
	// Object { }

What is a class?


class StrangeThing {
	upsideDown() {
		// some action
	}
}

console.log(StrangeThing);
	// function StrangeThing()

var instance = new StrangeThing();
console.log(instance);
	// Object {  }

🤔

Behaviour delegation


var Foo = {
	a: 'World',
	bar: function() {
		console.log(this.a);
	},
};

var Whoop = Object.create(Foo);
Whoop.a = 'Hello',

Whoop.bar(); // Hello

Foo.bar = function () { console.log('Fooled you!'); };
Whoop.bar(); // Fooled you!

Extending


var Foo = {
	a: 'World',
	bar: function() {
		console.log(this.a);
	},
};

var Whoop = Object.assign({}, Foo, { a: 'Hello' });

Whoop.bar(); // Hello

Foo.bar = function () {};
Whoop.bar(); // Hello

My advise:

Use composition

2. Moving forward

Modules and structure

"Do one thing, and do it well."

require vs import

Require


// someModule.js

module.exports = function someModule(input) {
	return input + 1;
}

// other file

var someModule = require('./someModule');

someModule(41); // 42

imports


// someModule.js

export default function someModule(input) {
	return input + 1;
}

// other file

import someModule from './someModule';

someModule(41); // 42

Named exports


// someModule.js

export function addTwo(input) {
	return input + 2;
}

export function addOne(input) {
	return input + 1;
}

// other file

import { addOne, addTwo } from './someModule';

addOne(addTwo(39)); // 42

Dynamic imports


import('./someModule')
	.then(({ addOne, addTwo}) => {
		addOne(addTwo(39)); // 42
	});

You'll need transpilers

Next generation JavaScript

or ES6 ES7 ES2015 ESNEXT...

Arrow functions


var returnFirstArg = param => param;
returnFirstArg(42, 'Hi', 13); // 42

var noArgs = () => 'Test';
noArgs(); // Test

var withArgs = (a, b, c, d) => a + b + c + d;
withArgs(12, 20, 8, 2); // 42

var withBody = () => {
	var something = 'Something';

	return something;
};

const and let


const hello = 'Hi';
hello = 'Overwrite';
	// TypeError: invalid assignment to const `hello'

let hi = 'Hello';

if (hi === 'Hello') {
	let hi = 'World';
	hi; // World
}

hi; // Hello

Template strings


const firstName = 'Gaya';
const surName = 'Kessler';

const fullName = `${firstName} ${surName}`;
	// Gaya Kessler

const multiline = `Well,
this is new!
Awesome.`;

const showName = true;
const expressions =
	`Hello ${showName ? firstName : 'you'}!`;
	// Hello Gaya

Destructuring


const Gaya = { name: 'Gaya', height: 184, age: 30 };

const { age, name } = Gaya;

Destructuring


const Gaya = ['Gaya', 184, 30];

const [name, height, age] = Gaya;

Spread operator


const Gaya = { name: 'Gaya', height: 184, age: 30 };
const Harry = { ...Gaya, name: 'Harry' };
	// { name: 'Harry', height: 184, age: 30 };

// same as

const Harry = Object.assign({}, Gaya, { name: 'Harry' });

Spread operator


const numbers = [1, 2, 3, 4, 5];
const floats = [0.2, 0.5, 3.72];

numbers.concat(floats);

// or
[...numbers, ...floats];
// [1, 2, 3, 4, 5, 0.2, 0.5, 3.72]

[...numbers, 6, 7, 8, 9, 10];
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

async await


async function fetchContent() {
	try {
		const result = await fetch('https://www.google.com');
		const text = await result.text();

		return text;
	} catch (e) {
		throw new Error(e.message);
	}
}

const text = await fetchContent();

Pure vs. Impure

Pure functions

  • no side-effects
  • given the same input, will always
    return the same output
  • are predictable
  • are very testable

Impure functions

  • Makes sense to call without
    using the return value
  • Can adjust external values

Some tips

  • Never touch arguments, copy them
  • Avoid using state in objects
    or this altogether
  • Most methods are better off as functions

Get the hang of (pure) Array functions

map reduce filter find

Composition

"a product of mixing or combining
various elements or ingredients"

Composing in JavaScript


function compose(...fns) {
	const reversedFns = [...fns].reverse();
	return (input) =>
		reversedFns.reduce((value, fn) => fn(value), input);
}

const roundString = compose(Math.round, parseFloat);
roundString('80.5'); // 81

const canLoose = (obj) => ({
	...obj,
	loose() { console.log(`${this.name} lost!`); }
});

const canWin = (obj) => ({
	...obj,
	win() { console.log(`${this.name} won!`); }
});

function createGame(input) {
	return canLoose(canWin(input));
	// or
	return compose(canLoose, canWin)(input);
}

3. Beyond the browser

Using babel & webpack

Problem! It's confusing and hard.

create-react-app

angular-starter

preact-cli

use linters and a styleguide

What I use

ESLint

airbnb-styleguide

Type strict JavaScript

Flow

Typescript

Try some Node.js

Thanks!

Gaya Kessler

Freelance Web Developer


https://theclevernode.com
@GayaKessler on Twitter