Tagged Template Strings ermöglichen zusätzliche Verarbeitung, wenn Werte eingebunden werden
Beispiele für Verwendungszwecke:
Beispiel: "Escaping" von HTML:
import { safeHtml } from 'common-tags';
const message = 'I <3 U';
const post = safeHtml`
<div>${message}</div>
`;
Ergebnis:
<div>I <3 U</div>
JavaScript versucht oft, keine Fehler zu werfen, sondern Resultate zu liefern (auch wennd diese keinen Sinn machen)
1 + "1"
→ "11"
parseInt("foo")
→ NaN
{} + []
→ 0
Math.sqrttt
→ undefined
Übung: versuche, diese Arten von Fehlern auszulösen
console.log(Mathhh);
→ ReferenceError: Mathhh is not defined
Math.sqrttt(2);
→ TypeError: Math.sqrttt is not a function
emptyArray[0].toUpperCase();
→ TypeError: Cannot read properties of undefined
mögliche Fehlerquellen:
Beispiel: Versuch, ungültiges JSON zu parsen
// invalid JSON string
let preferencesString = '{ theme: dark }';
let preferences;
try {
preferences = JSON.parse(preferencesString);
} catch {
// error while loading preferences - use default values
preferences = { theme: 'light' };
}
Beispiel: Fehler in node.js
try {
fs.writeFileSync('foo.txt', 'foo');
} catch {
console.log('could not write to file');
}
Zugriff auf das Fehler-Objekt:
try {
// ...
} catch (error) {
console.log(error.name); // SyntaxError
console.log(error.message); // JSON.parse: expected ...
}
Verwendung des finally-Blocks, der immer ausgeführt wird:
try {
let file = fs.openSync('foo.txt');
fs.writeSync(file, 'foo\n');
fs.writeSync(file, 'bar\n');
} catch {
console.log('error while writing - aborting');
return;
} finally {
// "clean up"
fs.closeSync('foo.txt');
}
const myNumbers = [1, 2, 3];
const newNumbers = myNumbers.map((n) => 3 * n);
// [3, 6, 9]
const myNumbers = [1, 2, 3, 4];
const isEven = (n) => n % 2 === 0;
const evenNumbers = myNumbers.filter(isEven);
// [2, 4]
const initialBalance = 300;
const transactions = [
{ amount: -50, title: 'groceries' },
{ amount: +1000, title: 'salary' },
{ amount: -10, title: 'dinner' },
{ amount: -100, title: 'electricity' },
];
const reducer = (aggregator, transaction) =>
aggregator + transaction.amount;
const currentBalance = transactions.reduce(
reducer,
initialBalance
);
// 300 -> 250 -> 1250 -> 1240 -> 1140
Beispiel für optional chaining:
const userNickname = user?.nickname;
wenn user
definiert ist, lies dessen .nickname
Property, andernfalls verwende undefined
"konventionelle" Langform:
const userNickname = user ? user.nickname : undefined;
Optional chaining mit Funktionsaufrufen:
props.onClick?.();
wenn props.onClick
definiert ist, wird es aufgerufen, andernfalls wird der Ausdruck zu undefined
ausgewertet
OOP in JavaScript basiert nicht auf Klassen, sondern auf sogenannten Prototypen
Vergleich aus dem echten Leben: Auto-Objekte
Eine Auto-Klasse wäre ein Bauplan für ein Auto
Ein Auto-Prototyp wäre ein bestehendes Auto auf dessen Vorlage weitere Autos gebaut werden können
Bei OOP in JavaScript beginnen wir damit, die Konstruktorfunktion zu schreiben, die ein Objekt initialisiert:
function Car(brand, model) {
this.brand = brand;
this.model = model;
}
Car.prototype.accelerate = function() {
console.log('wrooom!');
};
Car.prototype.getDescription = function() {
return this.make + ' ' + this.model;
};
var myCar = new Car('VW', 'Golf');
console.log(myCar);
console.log(myCar.getDescription());
myCar.accelerate();
class Car {
constructor(brand, model) {
this.brand = brand;
this.model = model;
}
accelerate() {
console.log('wroom!');
}
}
Vererbung
class LuxuryCar extends Car {
openRoof() {}
}
In Objektmethoden bezieht sich this
üblicherweise auf das aktuelle Objekt
allerdings:
object.method()
aufgerufen wirdclass Foo {
constructor() {
// this ist set correctly here
this.foo = true;
setTimeout(function () {
// this will be overwritten here (to 'window')
console.log(this.foo);
}, 1000);
}
}
class Foo {
constructor() {
// this ist set correctly here
this.foo = true;
setTimeout(() => {
// this will *not* be overwritten here
console.log(this.foo);
}, 1000);
}
}
class Foo {
constructor() {
this.message = 'hello';
}
greet() {
console.log(this.message);
}
}
const foo = new Foo();
foo.greet(); // ok
const greet = foo.greet;
greet(); // not ok ("this" is undefined)
Seit ES2018 einsetzbar:
class Foo {
constructor() {
this.message = 'hello';
}
greet = () => {
console.log(this.message);
};
}
const foo = new Foo();
foo.greet(); // ok
const greet = foo.greet.bind(foo);
greet(); // ok
Ãœblicherweise Zuweisung im Konstruktor:
constructor() {
this.greet = this.greet.bind(this);
}
verbreitete Libraries:
Ändern von Elementen
$('#myelement')
el.html('content')
el.css('color', 'blue')
el.addClass('abc')
el.prop('style')
Erstellen / hinzufügen / entfernen von Elementen
$('<div>')
parent.append(child)
child.remove()
Abfragen von Events
$(element).on('click', ...)
$(element).click(...)
Bietet insbesondere die Datenstrukturen List und Map als unveränderliche Alternativen zu Array und Object.
import { List, Map } from 'immutable';
const a1 = List([1, 2, 3]);
const a2 = a1.push(4);
const b1 = Map({ a: 1, b: 2 });
const b2 = b1.set('b', null);
import { fromJS, setIn } from 'immutable';
const todos = fromJS([
{ id: 1, title: 'groceries', completed: false },
{ id: 2, title: 'gardening', completed: false },
]);
const newTodos = todos.setIn([1, 'completed'], true);