Home » Beitrag verschlagwortet mit 'JavaScript'

Schlagwort-Archive: JavaScript

Javascript: Null, undefined, falsy, truthy

undefined‚ bedeutet, dass eine Variable nicht initialisiert wurde, z.B.:
let myVar;

Eigentlich ist ‚undefined‘ die falsche Benennung, da ja die Variable tatsächlich deklariert wurde! Eine Variable, die nicht deklariert wurde, kann man gar nicht abprüfen. Versucht man das wird das mit Fehlermeldung „… is not defined“ quittiert.

null ist eine Variable nur, wenn ’null‘ explizit zugewiesen wurde:
let myVar = null;

Check for null

myVar === null

Check for undefined

myVar === undefined

Check for null OR undefined

myVar == null

Truthy / Falthy

Als falsy gelten in JS:
0, „“ (leerer String), false, null und undefined

Diese Werte werden als false interpretiert.

„“ ist false!
0 ist false!

Module Pattern / Revealing Module Pattern

Module Pattern

Ziel:
– Objekt mit privaten Variablen erstellen

let person = (function () {
  let name = 'Veronika'; //Private Objektvariable

  return  {
    getName: function () { // Objekt-Methode 1
      return name;
    },
    setName: function (myName){ // Objekt-Methode 2
      name = myName;
    }
  };
})(); // Immediatly invoked function expression

person.name;
// undefined
person.getName();
// 'Veronika'

person.setName('Not Veronika');
person.getName;
// 'Not Veronika'

Das pattern beinhalted eine IIFE.
Ich empfinde das allerdings eher als Limitierung und erbringt bezüglich des Ziels (Objekt mit privater Variable erstellen) nichts.

Revealing Module Pattern

Das RMP unterscheidet sich zum MP nur diesbezüglich, dass das die public Funktionen nicht innerhalb des „return“-Blocks codert werden, sondern derselbige nur referenzen auf die Funktionen enthält:

let person = (function () {
  let privateAge = 0;
  let privateName = 'Andrew';

  function privateAgeOneYear() {
    privateAge += 1;
    console.log(`One year has passed! Current age is ${privateAge}`);
  }

  function displayName() {
    console.log(`Name: ${privateName}`);
  }

  function ageOneYear() {
    privateAgeOneYear();
  }

  return {
    name: displayName,
    age: ageOneYear
  };
})();

Mixins (JavaScript ‚Mehrfachvererbung‘)

Javascript kennt keine Mehrfachvererbung. Jedoch können mittel der Object.assign(target, source) Properties des einen Objektes auf ein anderes übertragen werden:

let target = {};

let source = { number: 7 };

Object.assign(target, source);

console.log(target);
// { number: 7 }

Einem Objekt können auch Properties von mehreren anderen Objekten injiziert werden:

const duck = {
  hasBill: true
};
const beaver = {
  hasTail: true
};
const otter = {
  hasFur: true,
  feet: 'webbed'
};

const platypus = Object.assign({}, duck, beaver, otter);

console.log(platypus);
// { hasBill: true, hasTail: true, hasFur: true, feet: 'webbed' }

Functional Mixins (–> Vererbungsmässige Komposition)

Code zeigt, wie mit Factory Funktionen geschachtelt aufgerufen werden um verschiedenen Eigenschaften/Methoden aus verschiedenen „Klassen“ zu komponieren:

function IceCreamFactory(obj) {
  let isCold = true;

  return Object.assign({}, obj, {
    melt: function () {
      isCold = false;
    },
    isCold: function () {
      return isCold;
    }
  });
}

let iceCream = IceCreamFactory({});

function ConeFactory(obj) {
  let isDry = true;

  return Object.assign({}, obj, {
    soggy: function () {
      isDry = false;
    },
    isDry: function () {
      return isDry;
    }
  });
}

let iceCreamCone = IceCreamFactory(ConeFactory({}));

console.log(iceCreamCone);

Angular Cheet Sheet

Regular Expression auf derzeitiger Web-Page als JavaScript (als Link/Bookmark) in der Browser URL ausführen

Dieser JavaScript-Link (kann gebookmarked) und aufgerufen werden um mit RegExp in der derzeitigen Page zu suchen:

javascript:(function(searchStr){console.log('SearchStr: ' + searchStr); var p=RegExp('(\\>{1}[^\n\\<]*?)([^\n\\<]{0,0}%27 + searchStr + %27[^\n\\<]{0,0})%27,%27gi%27); b=document.body; console.log(%27Pattern: %27 + p); console.log( document.body.innerText.match(p)); b.innerHTML=b.innerHTML.replace(p,%27$1<span style="background-color:red;">$2</span>%27);})(prompt(%27Was suchst du%27));

–> als link

Inspiriert von:

https://superuser.com/questions/417875/how-can-i-search-for-regular-expressions-within-webpages-using-google-chrome-or

RegExp mit Javascript:

https://stackoverflow.com/questions/884762/javascript-whats-the-point-of-regexp-compile

Jasmine – JavaScript testing

Jasmine ist ein sehr einfaches JUnit-Test-Werkzeug für JavaScript.
–> Extrahiert von: Udacity > Frontend Developer Nano Degree > 6. JavaScript Tools & Testing > Lesson 9: Writing Test Suites
–> Code

Alles was benötigt wird um ein JavaScript-Projekt zu testen:

Das SpecRunner.html:

Dieses wird einfach so im Browser geöffnet/refreshed und zeigt die Testergebnisse an.

Das SpecRunner.html enthält die ’script‘-Links zu …

a) … den benötigten Jasmine-Libraries
<script src=“lib/jasmine-2.2.0/jasmine.js“></script>
<script src=“lib/jasmine-2.2.0/jasmine-html.js“></script>
<script src=“lib/jasmine-2.2.0/boot.js“></script>

b) … den getesteten JavaScript-Files
<script src=“src/Player.js“></script>

c) … den tests:
<script src=“spec/Player.js“></script>

Die Tests

describe("AddressBook", function(){

    it("silly test", function() {
        let c = new Contact();
        let ab = new AddressBook();
        ab.addContact(c);
        expect(ab.getContact()).toEqual(c);
    });
});

Über die Funktion it(..) teilen wir Jasmine mit, dass wir einen Test mit einem gegebenen Namen und unter ausführung einer mitgegebenen Funktion ausführen wollen.

Über die Funktion expect(..) übergeben wir den Outcome und chainen den Reply auf eine Matcher-Funktion (toEqual(..) in unserem Beispiel.

Über die Funktion describe(..) teilen wir Jasmine die Testsuite mit und die Funktion, die es für diese ausführen soll.

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);
  }
}

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 wir als Parameter an die globale Funktion setTimeout übergeben. Die Funktion setTimeout ist also nicht Teil des Klasse2-Objekts und wenn setTimout dann die anonyme Funktion aufruft wird This nicht auf das Klasse2-Objekt zeigen! 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 }