Funktionale Programmierung mit Javascript - FH Rosenheim - AfP SS 2016 - Michael Haeuslmann & Marinus Noichl
Dauer: ~45min (exkl. Fragen)
Wer ist an der Hochschule bereits mit JavaScript in Berührung gekommen?
Wer arbeitet privat/beruflich mit JavaScript?
Wer meint JavaScript ist eine „schöne“ Sprache?
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.Window; public class HelloWorld implements EntryPoint { public void onModuleLoad() { Window.alert("Hello, World!"); } }
Python + Ruby + Haskell = ♥
# Conditions: number = -42 if opposite # Functions: square = (x) -> x * x # Splats: race = (winner, runners...) -> print winner, runners # Array comprehensions: cubes = (math.cube num for num in list)
class Greeter { constructor(public greeting: string) { } greet() { return "<h1>" + this.greeting + "</h1>"; } }; var greeter = new Greeter("Hello, world!"); document.body.innerHTML = greeter.greet();
var schlafEin = (anzahlSchafe) => { var i = 0, ausgabe = []; for (i = anzahlSchafe; i > 0; --i) { if (i === 1) { ausgabe.push(1 + " Schaf"); } else { ausgabe.push(i + " Schafe"); } } return ausgabe.join("\n") + "\nZzzz ..."; }; schlafEin(5);
// boolean true false // number 1 3.1415 (3.1415).toString() // string 'Hello' // regex /java[sS]cript/Alles ist ein Objekt (auch Funktionen selbst)!
// assoziatives Array (functioncal scope) var arr = [1, 2, 3]; // Objekte ähnlich wie JSON (global scope) obj = { bezeichner: 'wert' } // seit ES6: Map und Set // immutable Map (block scope) const map = new Map([[ 1, 'one' ]]); // Set (block scope) let set = new Set([1, 1, 1, 2]); // Set { 1, 2 }
// praktisch: kein List<Integer> list = new ArrayList<Integer>(); let list = [1, 2, 3, 4, 5]; // dynamisch typisiert, keine Initialisierung notwendig let organization = 'Microsoft'; // ⚡ neue Variable durch Schreibfehler ⚡ organisation = 'Google';
// schwach typisiert let x = 1; // number x = true; // boolean x = 'true'; // string
⚡ Abgesehen für kleine Skripte fast nur Nachteile ⚡
0 == '' // true 0 == '0' // true '' == '0' // false false == 'false' // false false == '0' // true " \t\r\n " == 0 // true
⚡ Typumwandlungen z.B. bei == != + ... ⚡
♥ immer === verwenden! ♥
var x = 3; function func(randomize) { var x; // geht nur da functional scope if (randomize) { // bei let error let x = Math.random(); return x; } return x; } func(false); // undefined
♥ immer let verwenden! ♥
var Animal = (function() { function Animal(name) { this.name = name; } Animal.prototype.move = function(meters) { return this.name + " moves " + meters + "m."; }; return Animal; })();
function Snake(name, isPoisonous) { Animal.call(this, name); // super(name) this.isPoisonous = isPoisonous; } Snake.prototype = Object.create(Snake.prototype); Snake.prototype.constructor = Snake; Snake.prototype.move = function (meters) { return this.name + " wiggles " + meters + "m."; };
class Animal { constructor(name) { this.name = name; } move(meters) { return this.name + " moves " + meters + "m."; } } class Snake extends Animal { move(meters) { return this.name + " wiggles " + meters + "m." } }
// imperative var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for (var i = 0, result = []; i < data.length; i++) { if (data[i] % 2 === 0) { result.push(data[i]); } } return result; // functional return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].filter(i => i % 2 === 0);
// imperative data = [0, 1, 2, 3]; for (var i = 0, result = []; i < data.length; i++) { result.push(data[i] * data[i]); } return result; // functional return [0, 1, 2, 3].map(i => i * i);
// imperative let sum = 0; for (const i of [1, 2, 3, 4]) { // neues immutable for seit ES6 sum += i; } return sum; // functional return [1, 2, 3, 4].reduce((i, j) => i + j);
Idee: Langsame externe Events asynchron verarbeiten und weitermachen bis das Ergebnis kommt
Ergebnis: Je nach Anwendungsbereich sehr hoher Durchsatz
fs.readFile('config.js', // some time passes... function(error, buffer) { // the result now pops into existence http.get(options, function(resp){ resp.on('data', function(chunk){ //do something with chunk }); }).on("error", function(e){ console.log("Got error: " + e.message); }); } );⚡ Callback Hell ⚡ Mehr imperativ als deklarativ ⚡
fs.promisifiedReadFile('config.js') .then(fetchSomethingFromWeb) .then(processThatData) .then(saveItToTheDatabase) .catch(function(error) { console.log(error); });
fs.promisifiedReadDir("/home/user/workspace") .map(fs.promisifiedReadFile) .reduce((total, content) => total += content.length, 0) .then(result => console.log(result)) .catch(error => console.log(error));
let add = function(a, b) { return a + b; } let add2 = (a, b) => a + b; let map = (fn, xs) => { if (!xs.length) return []; return [fn(xs[0])].concat(map(fn, xs.slice(1))); }; let inc = a => a + 1; map(inc, [0, 1, 2]);
let applyFn = (fn, x) => (y) => fn(x, y); let inc2 = applyFn(add, 1); let curry = (fn, ...args) => fn.length === args.length ? fn(...args) : curry.bind(this, fn, ...args); let inc3 = curry(add)(1);
let sort = xs => { if (xs.length === 0) return []; let pivot = xs[0], t = xs.slice(1); return sort(t.filter(x => x < pivot)) .concat(pivot) .concat(sort(t.filter(x => x >= pivot))); }