Home » 2021 (Seite 2)

Archiv für das Jahr: 2021

JavaScript ES6 Features

Template Literals

> name='Martin'
'Martin'
> surName='Büchner'
'Büchner'
> console.log(`Mein Name ist ${name} ${surName}.`);
Mein Name ist Martin Büchner.
undefined
>

Spread Operator / Destructuring

Array zu Einzelparameter

> nameArr = ['Hans', 'Müller'];
[ 'Hans', 'Müller' ]
> [vorname, name] = nameArr;
[ 'Hans', 'Müller' ]
> vorname
'Hans'
> name
'Müller'

//Auf Funktion anwenden:

> function showName2([vorname, name]){
... console.log(`Ich heisse ${name} ${vorname}.`);
}
undefined
> showName2(nameArr);
Ich heisse Müller Hans.
undefined
>

//Geht so nicht:
> function showName(name, vorname){
... console.log(`Ich heisse ${name} ${vorname}.`);
}
undefined

> showName(nameArr);
Ich heisse Hans,Müller undefined.
undefined

Objekt zu Einzelparametern


> person1 = {
...     name : 'Van Gough',
...     firstName : 'Vincent'
... };
{ name: 'Van Gough', firstName: 'Vincent' }
>
> let {name, firstName} = person1;
undefined
> name
'Van Gough'
> firstName
'Vincent'


//Ohne const, let geht es nicht:
> {name, firstName} = person1;
{name, firstName} = person1;
                  ^

Uncaught SyntaxError: Unexpected token '='

//Fraglich ist für mich, wozu das dient, denn die Variablen lassen sich nur einmal zuordenen:
> const {name, firstName} = person1;
Uncaught SyntaxError: Identifier 'name' has already been declared
> let {name, firstName} = person1;
Uncaught SyntaxError: Identifier 'name' has already been declared
> undef name

Einzelparameter zu Array

Variadische Funktion (Var Args)

> function variadischeFunktion(...liste){
...     for(i of liste){
.....         console.log(i);
.....     }
... }
undefined
>
> variadischeFunktion('Frühling','Sommer','Herbst','Winter')
Frühling
Sommer
Herbst
Winter
undefined
>

Einzelparameter zu Objekt

let name = 'Schutter';
let vorname = 'Heinz';

let person = {name, vorname};

> person
{ name: 'Schutter', vorname: 'Heinz' }

Rest Parameter

> arr1 = ['Karl', 'Gutenberg', 'Hofstr. 77', '3000', 'Bern'];
[ 'Karl', 'Gutenberg', 'Hofstr. 77', '3000', 'Bern' ]
> [vorname, name, ...adresse] = arr1;
[ 'Karl', 'Gutenberg', 'Hofstr. 77', '3000', 'Bern' ]
> name
'Gutenberg'
> vorname
'Karl'
> adresse
[ 'Hofstr. 77', '3000', 'Bern' ]
>

Iterator/Iterable (and Symbols)

Reference: https://javascript.info/iterable

Über Objekte, die die Iterable sind kann mit dem for of loop iteriert werden.

String und Array implementieren Iterable:

for(c of ‚Hans‘) console.log(c);
H
a
n
s
undefined


for(i of [49, 48, 25, 14, 10]) console.log(i);
49
48
25
14
10
undefined

Ein iterierbares Object referenziert auf [Symbol.iterator] einen Iterator. Anstatt über den For-Of-Loop kann man diesen auch explizit beziehen und dessen next()-Methode aufrufen. Es wir dabei ein Objekt mit dem eigentlichen Wert (Feld ‚value‘ zurückgegeben und ein Feld ‚done‘, dass besagt, ob die Iteration schon am Ende angekommen ist.

Ein eigenes Objekt iterable machen:

Ein Objekt (obj3) ist iterable sofern es unter Symbol 'Symbol.iterator' einen Iterator anbietet.
Ein Iterator zeichnet sich aus durch: Eine Methode next(), die ein Objekt {value : …, done: …} zurückgibt, wobei ‚value‚ das schrittgemässe Rückgebeobjekt referenziert und ‚done‚ besagt, ob die Iteration am Ende angekommen ist.

class MyIterator{
    constructor(){
        this.cnt = 0;
    }
    next(){
        return { value : { count : this.cnt++}, done : this.cnt > 2 };
    }
}
let obj3 = {
    [Symbol.iterator]() {
        return new MyIterator();
    }
}
//Test how this works:
for(o of obj3) console.log(o);
//Output:
//{ count: 0 }
//{ count: 1 }
//undefined

JavaScript Klassen und Vererbung (ES6)

class Dessert {
  constructor(calories = 250) {
    this.calories = calories;
  }
}

class IceCream extends Dessert {
  constructor(flavor, calories, toppings = []) {
    super(calories);
    this.flavor = flavor;
    this.toppings = toppings;
  }
  addTopping(topping) {
    this.toppings.push(topping);
  }
}

Traps/Fallen beim Java-Programmieren – Anfängerfehler

assertThat(booleanExpression)

Achtung! Der Ausdruck assertThat(booleanExpression) prüft nichts!

Falsch:

assterThat("Hans".equals("Peter")); // wird keine JUnit-Failed Test ausweisen!

Richtig:

assertThat("Hans").isEqualTo("Peter"); // wird JUnit-Failed Test ausweisen!

Javascript Function Scope

Auf was zeigt die This-Referenz in Funktionen?

  1. Bei obj.myFunction(..) –> This ist das Objekt obj.
  2. Bei Aufruf myFunction(..) –> This ist das globale Objekt (oder window).
  3. Innerhalb einer mit new aufgerufenen Funktion: This zeigt auf das Objekt, das erzeugt wird.
  4. Mit apply(thisObj, ..)/call(thisObj, ..) aufgerufen: Auf das mitgegebene thisObj.
  5. Bei Arrow-Functions (z.B. (..) => this.feld1 ): This zeigt auf das was in der unmittelbaren Umgebung der Funktion als this referenziert wird.

This bei Arrow-Funktionen:

Bei Arrow-Funktions zeigt das this auf this der unmittelbaren Umgebung der Arrow-Function.

Im folgenden Beispiel wird obj2.increase2() aufgerufen. Das heisst: Innerhalb von increase2() ist this=obj2.
Das Problem: Die Anonyme Funktion innerhalb setTimeout wird mit keinerlei this-Kontext aufgerufen! Deshalb wird nicht feld1 von obj2 hinuaufgezählt, sondern es wird versucht feld1 im globalen Kontext zu finden. obj2.feld1 bleibt 0.

> Klasse2 = function(){
... this.feld1 = 0;
}

> Klasse2.prototype.increase2 = function(){
... setTimeout(function(){
..... this.feld1++
..... }, 500);
}

> obj2 = new Klasse2();
Klasse2 { feld1: 0 }
> obj2.increase2();
undefined
> obj2;
Klasse2 { feld1: 0 }
>

Damit die innere/anonyme Funktion auf obj2.feld1 zugreift müssen wir ihr explizit eine Referenz auf das umgebende this übergeben:

2. Variante der Methode

> Klasse2.prototype.increase3 = function(){
... saveThis = this;
... setTimeout(function(){
..... saveThis.feld1++;
..... }, 500);
... }
[Function]
> obj2.increase3();
undefined
> obj2;
Klasse2 { feld1: 1 }

Wenn wir aber die innere/anonyme Funktion als Arrow-Function definieren ist dieses This-Preserving unnötig, weil:
Das This von Arrow-Functions zeigt immer auf das This der unmittelbaren Umgebung!

3.Variante: Mit Arrow-Function:

>  Klasse2.prototype.increase4 = function(){
... setTimeout(() => this.feld1++, 500);
... }
[Function]
> obj2.increase4()
undefined
> obj2
Klasse2 { feld1: 2 }

Javascript Function: call(), apply(), bind()

–> Ref: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function

Funktionen können anstatt direkt (meineFuktion(p1, p2)) auch über meinObjekt.meineFuktion.call(thisRef, p1, p2) oder meinObjeckt.meineFunktion.apply(thisRef, [p1, p2]) aufgerufen werden.

Dies ermöglicht es die Funktion z.B. als Callback an weiter zu geben und dabei aber auch via This-Referenz das Objekt, auf dem die Funktion wirken soll. –> siehe 2 Vorsicht bei Übergabe von Funktionen!!

Mit funktionMitObjektMitgabe = meinObjekt.meineFuktion.bind(thisReferenz) wird erstens eine Fuktion erzeugt, die auf ein definiertes This-Objekt wirkt, die dann z.B. so aufgerufen werden kann: funktionMitObjektMitgabe(p1, p2)
–> siehe auch 2 Vorsicht bei Übergabe von Funktionen!!

Javascript Prototype und Prototype-Check-Funktionen

Alle JS-Objekte besitzen eine Prototype-Chain. Den Entrypunkt dazu findet man auf ein Objekt o1 via o1.__proto__.

Interessante Methoden um den Prototype (und damit Vererbungsbeziehungen) zu prüfen sind:

MethodeBeschrieb
hasOwnProperty()Prüft, ob eine Klasse oder ein Objekt ein Property hat, das es selbst, also nicht vom Prototypen her besitzt.
a.isPrototypeOf(b)Der Methoden-Name sagt alles.
Object.getPrototypeOf(o1); Selbsterklärend

Vererbung in JavaScript – Unglaublich kompliziert!

Dieser Beitrag ist überholt. Er zeigt, wie man Klassen und Vererbung vor ES6 löste.

Mit ES6 macht man das viel einfacher: JavaScript Klassen und Vererbung (ES6) (–> Udacity Artikel)


Klassen und Vererbung vor ES6 – Unglaublich kompliziert

Ich möchte Katze von Tier ableiten. In JavaScript. Wie gehe ich vor?

//1. Die Parent-Klasse definieren:
> function Tier(name){
... this.name=name;
... this.sayName=function(){ console.log(`Ich bin ${name}.`);}
}
undefined


//2. Die Kind-Klasse definieren
> function Katze(name){
... Tier.call(this, name); // Den Parent-Konstructor unter mitgabe von this aufrufen!
... this.hatFell=true;
}
undefined

//3. Ein neues (Prototype-)Objekt erstellen, das als Prototype denjenigen 
//   vom Parent-Objekt hat. Dieses Objekt als Prototype vom Child anlegen.
> Katze.prototype = Object.create(Tier.prototype)
Tier {}


//4. Den Konstruktor vom Child wieder auf denjenigen vom Child zurücksetzen:
> Katze.prototype.constructor = Katze;
[Function: Katze]
>

Benutzung:

> katze1 = new Katze('Kitty');
Katze { name: 'Kitty', sayName: [Function], hatFell: true }
> katze1.sayName();
Ich bin Kitty.
undefined
>

JavaScript Constructor Field

Auf den Konstruktor der einem Java-Objekt o zu Grunde liegt kann über o.constructor zugegriffen werden.

Wie man diesen Konstruktor dann benutzen kann um neue Objekte zu erstellen zeigt folgende Code-Sequenz:

Anlegen der Klasse Mensch und instantieren derselben

> function Mensch(name, gender){
... this.name=name;
... this.gender=gender;
... this.sayHello = function(){
..... console.log(`Hallo, ich bin ${this.gender} ${this.name}!`);
..... }
... }
undefined
> h1 = new Mensch('Schmid', 'Herr')
Mensch { name: 'Schmid', gender: 'Herr', sayHello: [Function] }
> h1.sayHello()
Hallo, ich bin Herr Schmid!

Um nun den Konstruktor der Instanz zu benutzen um weitere Objekte zu instanzieren:

> kl = {};
{}
> l.constructor.call(kl,'Lagerfeld', 'Herr');
undefined
> kl
{ name: 'Lagerfeld', gender: 'Herr', sayHello: [Function] }
> kl.sayHello()
Hallo, ich bin Herr Lagerfeld!
undefined
>

Es muss also zuerst eine Objekt erstellt werden. Dieses Objekt kann dann constructor.call(obj, param, …) mitgegeben werden um das Objekt mit den mittels Konstruktor zu ‚befruchten‘.

IIFE in JavaScript

Immediately invokes function expressions: Das sind Funktionsdefinitionen, welche durch das hinten Anhängen eines () sofort aufgerufen werden.

function(){console.log("Schon ausgeführt!";}(); 

Hier ein interessanter Anwendungsfall einer IIFE:

Dieses script.js file zeigt einen anwendungsfall einer IIFE. Dem ‚onclick‚-Ereignis des Buttons wird eine Funktion ‚countAlerter‚ zugeordnet. (Auf den ersten Blick scheint es zwar, die äussere, anonyme Funktion werde zugeordnet, was nicht stimmt, denn diese wird ja direkt mit ‚()‚ aufgerufen und der Rückgabewert dieses Aufrufs wird onclick zugordnet.) Da countAlerter aber innerhalb einer enclosing Function definiert ist behält die countAlerter die darin enthaltene (Objekt-)Variable ‚clickCount‘ in seiner Closure.

let button = document.getElementById("b1")
button.onclick = function(){
    let clickCount = 0;
    return function countAlerter(){
        alert('Click nbr ' + clickCount++);
    }
}();

Diese Funktion gibt also bei jedem Klick auf den Button die bereits getätigte Anzahl Klicks aus.