Arrow-Function
Verkürzte Schreibweise einer Funktion. Seit ES6 verfügbar.
Schlüsselwort function entfällt
dafür wird fat arrow (
=>) gesetztwenn nur ein Parameter übergeben wird, können () entfallen
Syntax:
let bezeichner = () => {};
let bezeichner = para => {};
let bezeichner = (para1, para2) => {};
Bei kurzen Statements können {} weggelassen werden. Hier wird der Wert
des Statements implizit zurückgegeben:
let bezeichner = (p1,p2) => p1 * p2;
Bei mehreren Statements müssen {} hingegen gesetzt werden.
Das Schlüsselort this verhält sich in Arrow-Funktions anders, als in
regulärer definierten Funktionen:
/*
Schlüsselwort 'this'
mit 'this' spricht man innerhalb einer Objektmethode (oder Konstruktor)
die jeweilige Objektinstanz an => das aktuelle Objekt / dieses Objekt (Kontext-Objekt)
this = impliziter Parameter von Funktionen
wird beim Aufruf der Funktion mit Kontext-Objekt belegt, auf dem Funktion aufgerufen wird
this kann nicht geändert werden
this referenziert immer Objekt, in dessen Kontext Funktion aufgerufen wird
Ausnahme = arrow-Function
*/
let person_1 = {
firstName: "Jessica",
age: 36,
myMethod () {
console.log(this); // Object {firstName: "Jessica", ...}
}
};
person_1.myMethod();
function myNewFunc() {
console.log(this); // undefined
}
myNewFunc(); // undefined
Important
Arrow Funktionen haben kein eigenes Bindung für ‘this’ (ebenso ‘arguments’ und ‘super’) und sollten daher nicht für Methoden von Objekten verwendet werden.
Keine Arrow-Funktionen innerhalb von Objekten verwenden
/*
this befindet sich in Funktion außerhalb eines Objektes
daher bezieht sich this auf umliegenden Raum und hat kein Kontext-Objekt => undefined
ohne strikten Modus wird window-Object referenziert
*/
function getName() {
return this.firstName;
}
let getName2 = () => this.firstName;
/*
mit arrow-Function referenziert this das Objekt, in dem Funktion definiert wurde
im strikten Modus -> this = undefined
Kontext-Objekt von this = Objekt, in dem Funktion definiert ist
nicht Kontext, in dem sie aufgerufen wird
*/
let person_2 = {
firstName: "Jessica",
age: 36,
getName,
getName2
};
console.log(person_2.getName()); // "Jessica"
console.log(person_2.getName2()); // undefined
// wenn Funktion in Objekt gezogen und auf diesem aufgerufen wird,
// wird Bezug zum Kontext-Objekt hergestellt
// arrow-Function nicht für ausgelagerte Funktionen mit Kontakt zu this erstellen!
let person_3 = {
firstName: "Elektra",
age: 28,
myFunc() {
let myInnerFunc = function() {
console.log(this);
};
myInnerFunc();
}
};
person_3.myFunc(); // undefined
/*
bei Nutzung von this in innerer Funktion fällt this aus Kontext heraus
im stricten Modus => undefined
sonst window-object
*/
let person_4 = {
firstName: "Elektra",
age: 28,
myFunc() {
let myInnerFunc = () => console.log(this);
myInnerFunc();
}
};
person_4.myFunc(); // Object { firstName: "Elektra", ... }
/*
um Bezug zum Objekt wieder herzustellen => arrow-Function nutzen
this referenziert Kontext-Objekt, in dem innere Funktion definiert wird
Objekt wird zurück gegeben
*/
document.addEventListener("click", function() {
console.log(this);
}); // HTMLDocument
document.body.addEventListener("click", function() {
console.log(this);
}); // <body>
document.addEventListener("click", () => console.log(this)); // window
document.body.addEventListener("click", () => console.log(this)); // window
/*
Zusammenfassung - Kontakt mit this
wann normale Funktion - wann arrow-Function?
- im Raum außerhalb von Objekten => funktionsdeklaration oder funktionsausdruck
- in callback => arrow-function
- innerhalb von objekt-Methoden => arrow-function
- in Konstruktor-Funktionen => keine arrow Function zur Erzeugung von Objekten nutzbar
Eigenschaften von arrow-Function:
- referenzierter Wert von this ergibt sich aus Kontext, in dem Funktion definiert wirde!
nicht aus Kontext, ion dem sie ausgeführt wird!
*/
Higher Order Functions
Funktionen können als Argumente an andere Funktionen übergeben werden
function sayHello(nameFunc) {
console.log(`Hallo ${nameFunc()}`);
}
function giveName () {
return "Jessica";
}
sayHello(giveName); // Hallo Jessica
sayHello(function() {return "Luke";}); // Hallo Luke
sayHello(() => "Odin"); // Hallo Odin
let logHello = function (callbackfunction) {
callbackfunction("Hallo Duda");
};
logHello(function(text) {console.log(text);}); // Hallo Duda
sort()
Sortiert anhand der UTF16-Zeichentabelle.
let heroes = ["Jessy", "Elektra", "Loki", "Thor"];
console.log(heroes.sort()); // [ "Elektra", "Jessy", "Loki", "Thor" ]
[Array].sort(compareFn) erlaubt eine Sortierfunktion, welche zwei Argumente (a und b)
benötigt. Rückgabewerte:
negativer Wert => a kommt vor b
positiver Wert => b kommt vor a
0 oder NaN 0 => a und b sind identisch
let numbers = [1,5,99,11,22,20,3,10,62,63,6,600];
let numberCheck = function(a,b) {
console.log(`${a} - ${b} = ${a - b}`);
return a - b;
};
console.log(numbers.sort(numberCheck)); // [ 1, 3, 5, 6, 10, 11, ... ]
/*
sort() = higher order
numberCheck() = callback
callback wird an higher order übergeben
wird von higher order eigenständig mit argumenten aufgerufen
Verarbeitung in higher order erfolgt auf Grundlage des Rückgabewertes der callback
*/
heroes = ["Jessica", "Luke", "Odin (Chef)", "Thor", "Elektra"];
// Regel: Chef nach vorne, Rest alphabetisch
let isChef = hero => hero.endsWith("(Chef)");
let sortHeroes = (hero1, hero2) => {
if (isChef(hero1)) return -1; // Chef schon vorne --> nicht sortieren
if (isChef(hero2)) return 1; // Chef hinten --> nach vorne sortieren
return (hero1 > hero2) ? 1 : -1;
// ist hero1 hinter hero2 --> nicht sortieren, daher positiv
// ansonsten --> sortiere, daher negativ
};
console.log(heroes.sort(sortHeroes)); // [ "Odin (Chef)", "Elektra", "Jessica", "Luke", "Thor" ]
forEach()
Als Ersatz für eine for-Schleife für Arrays.
/*
ersetzt for-Schleife für Arrays
durchläuft Array Element für Element
erwartet callback
übergibt an callback:
1. Array-Element
2. index-Position --> optional
3. Ursprungsarray --> optional
erwartet keinen Rückgabewert von callback
lässt sich auf NodeList anwenden - aber nicht auf HTMLCollection
*/
let jahresZeiten = ["Frühling", "Sommer", "Herbst", "Winter", "Eiszeit"];
// array element, index-position, ursprungsarray
jahresZeiten.forEach( (elem, index, array) => {
console.log(index, elem); // 0 Frühling -> 1 Sommer -> ...
console.log(array); // [ "Frühling", "Sommer", "Herbst", "Winter", "Eiszeit" ]
});
// nur array element
let numbers = [1,5,99,11,22,20,3,10,62,63,6,600], sum = 0;
numbers.forEach( zahl => sum += zahl);
console.log(sum); // 902
// array element, index position
let paraList = document.querySelectorAll("p");
console.log(paraList);
paraList.forEach( (tag, i) => console.log(i, tag.textContent)); // 0 text -> 1 text -> ...
map()
Durchläuft ein Array Element für Element und erstellt ein neues Array, wobei jedes Element durch eine Callback-Funktion verändert werden kann.
/*
durchläuft Array Element für Element
erwartet callback
übergibt an callback:
1. Array-Element
2. index-Position
3. Ursprungsarray
erwartet Rückgabewert von callback
erstellt ZielArray (Kopie des Arrays)
Rückgabewerte der Callback werden Zielarray geschrieben
lässt sich nicht auf arrayartige Gebilde anwenden
mit Array.from() kann arrayartiges Gebilde in Array konvertiert werden
*/
let heroes = ["Jessica", "Luke", "Odin", "Thor", "Elektra", "Nebula"];
let makePassword = (hero, i) => {
let password = i;
password += hero.split("").reverse().join("") // Name spiegeln
password += hero.length;
return password;
};
let passwordArray = heroes.map(makePassword);
console.log(passwordArray); // [ "0acisseJ7", "1ekuL4", ... ]
// oder... (mit Arrow-Function)
let numbers = [1,5,99,11,22,20,3,10,62,63,6,600]
let squares = numbers.map( zahl => Math.pow(zahl, 2) );
console.log(squares); // [ 1, 25, 9801, ... ]
filter()
Mit .filter() lassen sich Einträge in einem Array filtern.
/*
durchläuft Array Element für Element
erwartet callback, in der Bedingungsprüfung stattfindet
übergibt an callback:
1. Array-Element
2. index-Position
3. Ursprungsarray
erwartet Rückgabewert (boolean) von callback
erstellt ZielArray mit Elementen, auf die callback mit true geantwortet hat
Bedingungsprüfung findet in callback statt
lässt sich nicht auf arrayartige Gebilde anwenden
mit Array.from() kann arrayartiges Gebilde in Array konvertiert werden
*/
let heroes = ["Jessica", "Luke", "Odin", "Thor", "Elektra", "Nebula"];
let avengers = heroes.filter( hero => hero.length > 4 );
console.log(avengers); // [ "Jessica", "Elektra", "Nebula" ]
let filtered = [1,42,52,53,62,99,111,7,9,3].filter( zahl => zahl > 9);
console.log(filtered); // [ 42, 52, 53, 62, 99, 111 ]
reduce()
Reduziert Elemente eines Arrays auf einen einzelnen Wert.
/*
reduziert Elemente eines Arrays auf einen einzelnen Wert
benötigt callback, in der Reduktion definiert wird
reduce() übergibt 2 Argumente an callback
callback reduziert auf einzelnen Wert und gibt diesen zurück
reduce() übergibt Rückgabewert mit nächstem Array-Element
...
bis nur noch ein Wert vorhanden ist (= Rückgabewert von reduce)
lässt sich nicht auf arrayartige Gebilde anwenden
mit Array.from() kann arrayartiges Gebilde in Array konvertiert werden
*/
let numbers = [1,5,99,42,53,62,11,9,73];
let add = (a,b) => {
console.log(`${a} + ${b} = ${a + b}`);
return a + b;
};
let total = numbers.reduce(add);
console.log(total); // OK: 355
let sum = array => array.reduce(add);
console.log(sum([52,63,41,11])); // OK: 167
console.log(sum([52])); // 52 wird zurückgegeben
// console.log(sum([])); // Uncaught TypeError: reduce of empty array with no initial value
/*
Initialwert kann als 2. Argument an reduce() übergeben werden
Wert muss zur Reduktion passen
dient der Vermeidung von TypeError bei Übergabe eines leeren Arrays
*/
let sumWithInitial = array => array.reduce(add, 0);
console.log(sumWithInitial([])); // 0
// reduceRight(cbf [, initial value])
// arbeitet wie reduce(), jedoch von rechts nach links
Array prüfen
/*
every() - prüft, ob ALLE Elemente einer Bedingung entsprechen
some() - prüft, ob MINDESTENS EIN Element einer Bedingung entspricht
higher order übergibt ein Array-Element an callback function
in callback function wird anhand definierter Bedingung geprüft und boolean
als Ergebnis zurückgegeben
Rückgabe der higher order = boolean
*/
let numbers = [2,21,42,3,9];
let even = zahl => {
console.log(zahl, !(zahl % 2));
return !(zahl % 2);
};
console.log(numbers.every(even)); // false
console.log(numbers.some(even)); // true
Elemente finden
Über find(), findIndex() sowie findLast(), findLastIndex()
lassen sich Elemente in einem Array finden.
let numbers = [21,42,3,10,9];
let even = zahl => {
console.log(zahl, !(zahl % 2));
return !(zahl % 2); // even: !0 --> true; odd: !1 --> false
};
/*
find()
liefert 1. Element eines Arrays, dass einer in callback function
definierten Bedingung entspricht
ohne Fund: undefined
*/
console.log(numbers.find(even)); // 42
/*
findIndex()
liefert die Indexposition eines Elements in einem Array, dass einer
in callback function definierten Bedingung entspricht
ohne Fund: -1
*/
console.log(numbers.findIndex(even)); // 1
/*
findLast() und findLastIndex() funktionieren genau so wie find() und
findIndex(), arbeiten jedoch von rechts nach links
*/
console.log(numbers.findLast(even)); // 10
console.log(numbers.findLastIndex(even)); // 3
Spread-Syntax
Werte aus Objekten oder Arrays werden aufgeteilt, als einzelne Werte übergeben.
/*
...bezeichner
Syntax teilt Werte von Arrays und Objekten auf
*/
let add = function(a = 0, b = 0, c = 0, d = 0) {
console.log(a,b,c,d);
console.log(a + b + c + d);
};
let numbers = [42,62,99,11];
add(...numbers); // Elemente von numbers werden einzeln übergeben
console.log(Math.max(...numbers)); // 99
console.log(Math.min(...numbers)); // 11
// für Arrays
let obst = ["Apfel", "Kirsche", "Pflaume", "Birne"];
let mehr_obst = ["Banane", "Kiwi", "Orange", ...obst, "Mandarine"];
console.log(mehr_obst);
// für Objekte
let user = {
name: "Jessica",
age: 36,
status: "angry"
};
let marvelHero = {
subject: "Comic Hero",
...user,
vote: 42
};
console.log(marvelHero);
// Beispiel: Date-Object
let dateArr = [2024,11,11];
let date = new Date(...dateArr);
console.log(date);
Unterschiede beim Duplizieren von Objekten
Die Spread-Syntax sollte nicht für das Erstellen von Objekten verwendet werden, da hier Referenzen übergeben werden.
const myUser = {
name: "Jessy",
age: 36,
address: {
street: "dragonroad",
number: 66,
city: "Hells Kitchen"
}
};
const myUser2 = {...myUser}; // Vorsicht: myUser2 referenziert Attribute von myUser (keine Kopie)!
myUser2.name = "Luke"
const myUser3 = JSON.parse(JSON.stringify(myUser));
const myUser4 = structuredClone(myUser);
myUser.address.number = 111;
console.log(myUser); // ok
console.log(myUser2); // ok --> Hausnummer wird auch geändert!
console.log(myUser3); // ok
console.log(myUser4); // ok
console.log(myUser.address.number); // ok
console.log(myUser2.address.number); // ok --> Hausnummer wird auch geändert!
console.log(myUser3.address.number); // ok
console.log(myUser4.address.number); // ok
// Die Spread-Syntax übermittelt Werte als Referenzen. Wird das Ursprungs-Objekt
// verändert, wird dies auch auf die Referenzen angewandt
// => Besser keine Objekte mit Spread-Syntax duplizieren!
Warning
Die Spread-Syntax erzeugt flache Kopien, d.h. nur Referenzen werden erzeugt.