Going functional with Vanilla JS

Going functional

Zkoušíme funkcionální programování

VanillaJS edition

Hit L to toggle language

Jazyk lze přepnout klávesou L

Ondřej Žára, @0ndras

VanillaJS

Functional programming

Funkcionální programování

FP: Building stones

FP: Stavební kameny

FP: Advantages of pure functions

FP: Výhody čistých funkcí

Buzzword showcase

Hitparáda buzzwordů

FP: Enemies

FP: Nepřátelé

FP: TCO

  1. Total Cost of Ownership
  2. Tjänstemännens Centralorganisation (Swedish Confederation of Professional Employees)
  3. Tail Call Optimisation

FP: Tail Call Optimisation

function x() { ... return y(); }

FP: Philosophy

FP: Filozofie

Functional programming in JS

Funkcionální programování v JS

Bad example: loop elimination

Špatný příklad: eliminace cyklu

function add(numbers) { if (numbers.length > 2) { return numbers[0] + add(numbers.slice(1)); } else { return numbers[0] + numbers[1]; } }

Bad example: evaluation

Špatný příklad: zhodnocení

Better example

Lepší příklad

function plus(x, y) { return x + y; } function add(numbers) { return numbers.reduce(plus); }

Better example: evaluation

Lepší příklad: zhodnocení

Built-in functional iteration

Vestavěná funkcionální iterace

You should be at least marginally familiar with these

O těchto bychom již měli mít alespoň základní ponětí

Real-life example

Příklad skutečného kódu

Address book: an array of people, every person has several e-mails. Who is on the blacklist?

Pole osob v adresáři, každá má několik e-mailů. Kdo je na blacklistu?

return people.filter(person => person.emails.some(email => blacklist.includes(email) ) })

Real-life example: evaluation

Příklad skutečného kódu: zhodnocení

By the way: taking care of variadic functions!

Odbočka: pozor na variadické funkce!

const str = "rgb(1, 5, 10)"; let [r,g,b] = str.match(/\d+/g).map(parseInt); // 1, NaN, 2 /* parseInt("1", 0, arr); parseInt("5", 1, arr); parseInt("10", 2, arr); */ let [r,g,b] = str.match(/\d+/g).map(Number); // 1, 5, 10

What if we do not use Arrays to store data

Když jsou data jinde, než v poli

FP has been in JS for ages

FP v JS od pradávna

[10, 1, 2].sort(); // [1, 10, 2] ‽ [10, 1, 2].sort( (a,b) => a-b ); // [1, 2, 10] DATA.sort((a, b) => { return a.name.localeCompare(b.name) });

FP has been in JS for ages

FP v JS od pradávna

"Hello %s!".format("world"); String.prototype.format = function(...args) { return this.replace(/%s/g, match => args.shift()); } String.prototype.format = function(...args) { return args.reduce((str, arg) => str.replace(/%s/, arg), this); }

Partial application

Částečné vyhodnocení (partial application)

add x y = x + y add2 = add 2 add2 3 = 5 function add(x, y) { return x + y; } var add2 = add(2); // ??? var add2 = partial(add, 2); // no built-in support

Partial application: bind

Částečné vyhodnocení: bind

function partial(func, ...args) { return func.bind(null, ...args); } var add2 = partial(add, 2); add2(3); // 5

More real life FP

Další ukázky FP

// do not try .apply for large arrays function min(array) { return array.reduce( (a, b) => Math.min(a, b) ); } function minAge(array) { return array.reduce( (a, b) => a.age < b.age ? a : b ); }

More real life FP

Další ukázky FP

function clone(value) { if (value instanceof Array) { return value.map(clone); } else if (value instanceof Object) { return Object.entries(obj).reduce(merge, {}); } else return value; } function merge(object, [key, value]) { let partial = { [key]: clone(value) }; return Object.assign(object, partial); }

Closing remarks

Poučení

Questions and answers

Prostor pro otázky

Homework

Domácí úkol

function myNew(ctor, ...args) { let inst = Object.create(ctor.prototype); let result = ctor.apply(inst, args); return (typeof(result) == "object" ? result : inst); }