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?
[...] you have the power to define your own subset. You can write better programs by relying exclusively on the good parts. - Douglas Crockford, JavaScript - The Good Parts
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 "" + this.greeting + "
";
}
};
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);
L1-Cache | 3 cycles |
L2-Cache | 14 cycles |
RAM | 250 cycles |
Disk | 41 000 000 cycles |
Network | 240 000 000 cycles |
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)));
}