SlideShare ist ein Scribd-Unternehmen logo
1 von 64
Downloaden Sie, um offline zu lesen
EntwicklerCamp 2010
Track 2, Session 4:
JavaScript für Fortgeschrittene



                                Gelsenkirchen, 9. März 2010


Innovative Software-Lösungen.
www.assono.de
Thomas Bahn

Diplom-Mathematiker, Universität Hannover
seit 1997 entwickle ich mit Java und
relationalen Datenbanken
seit 1999 mit Notes/Domino zu tun:
Entwicklung, Administration, Beratung und Schulungen
regelmäßiger Sprecher auf nationalen und
internationalen Fachkonferenzen zu IBM Lotus Notes/
Domino und Autor für THE VIEW

    tbahn@assono.de
    http://www.assono.de/blog
    04307/900-401

www.assono.de                                     Seite 2
Variablendeklaration

- Variablen-Deklaration:
  var name;

- Variablen-Deklaration kombiniert mit Wertzuweisung:
  var name = wert;

- SSJS-Spezialität: typisierte Variablen-Deklaration:
  var name : typ = wert;

- Prüfung, ob Variable deklariert ist
   - häufig, aber vereinfacht: if (a) {...}
    - Vorsicht: der Block wird auch ausgeführt, wenn a
      gleich false, null, "" oder 0 ist
    - besser: if (typeof a !== „undefined“) {...}

www.assono.de                                       Seite 3
Variablentypen

- „loose typing“ heißt nicht untypisiert!
- Es gibt folgende 6 Typen:
   - Strings
   - Numbers
   - Booleans
   - Objects
   - null
   - undefined




www.assono.de                               Seite 4
Spezielle Strings

-       Maskierungszeichen

-  ein Rückwärtsstrich 

- ' ein einfacher Anführungsstrich

- " ein doppelter Anführungsstrich

- n neue Zeile (newline)

- r “Wagenrücklauf“ (carriage return)

- t Tabulator

- u Unicode-Zeichen, z. B. u042F => Я


www.assono.de                             Seite 5
Zahlen

- alle Zahlen sind 64-bit Gleitkommazahlen („double“)
- Rundungsdifferenzen durch Binär-Dezimal-
  Konvertierung

- Bit-Shifting (<<, >>) möglich, aber kontraproduktiv




www.assono.de                                       Seite 6
Zahlen (forts.)

- 0x Präfix für Hexadezimalzahl-Literale, z. B. 0xFF
  0 Präfix für Oktalzahl-Literale, z. B. 014 (=12)

- Achtung bei parseInt(),
  z. B. parseInt(08) => Fehler!,
  insbesondere bei Benutzereingaben, z. B. beim Monat

- daher besser immer bei parseInt() die Basis (radix)
  als zweiten Parameter mit angeben:
  parseInt("08", 10);




www.assono.de                                          Seite 7
Zahlen (forts.)

- NaN = Not a Number
   - „ansteckend“
   - ungleich allem anderen (inklusive NaN)
    - testen mit isNaN()
    - typeof NaN => "number"




www.assono.de                                 Seite 8
Zahlen (forts.)

- Infinity = unendlich,
    - z. B. a/0 => Infinity
    - zumindest größer als die größte gültige Zahl:
      Infinity > 1.7976931348623157e+308

- -Infinity
   - ist absolut kleiner als die kleinste gültige Zahl:
     5e-324 > -Infinity

- beide „ansteckend“ bei Berechnungen, aber
   - 1/Infinity => 0
    - Infinity/Infinity => NaN



www.assono.de                                             Seite 9
Boolean

- !      logisches Nicht

- && logisches Und

- || logisches Oder

- „lazy evaluation“: nur berechnen, wenn noch nötig
- Beispiel:
  var a = 1; true || (a = 2) => a ist noch 1




www.assono.de                                     Seite 10
„Falsche“ Werte

- Folgende Werte sind „falsch“ (falsy):
   - false
   - null       („leer“, bewusst gesetzt)
    - undefined   (uninitialisiert oder nicht vorhanden)
    - ""          (leere Zeichenkette)
    - 0
    - NaN

- Alle anderen Werte sind true, auch
   - "0"
   - "false"



www.assono.de                                        Seite 11
Vergleiche

- ==            Gleichheit ggf. nach Typumwandlung
- !=            Ungleichheit ggf. nach Typumwandlung
- ===           Gleichheit ohne Typumwandlung
- !==           Ungleichheit ohne Typumwandlung
- Beispiele
   - "1" == 1 ist wahr
    - "1" === 1 ist falsch




www.assono.de                                          Seite 12
Vergleiche (forts.)

- switch
   - Vergleich ohne Typumwandlung
- a ? b : c
   - ternärer Operator
   - wenn a wahr ergibt, ist das Ergebnis b, sonst c




www.assono.de                                          Seite 13
Guard-Operator: &&

- && ist logisches Und

- Beispiel:
  return obj && obj.member;

- gibt obj.member zurück, wenn obj nicht undefined
  oder null ist (oder präziser: nicht false ist)

- aber Vorsicht, wenn false, null, "", 0 gültige Werte
  sein können!




www.assono.de                                     Seite 14
Default-Operator: ||

- || ist logisches Oder

- Beispiel
  var value = arg || "Vorgabewert";

- wenn arg nicht „falsch“ ist, wird value arg
  zugewiesen, sonst "Vorgabewert"

- aber Vorsicht, wenn false, null, "", 0 gültige Werte
  sein können!
- nützlich bei optionalen Parametern einer Funktion




www.assono.de                                         Seite 15
Noch mehr Operator-Magie

- + als unärer Operator wandelt Strings um in Zahlen:
  +"1" === 1

- !! wandelt um in Boolean:
  !!"1" === true




www.assono.de                                     Seite 16
typeof-Operator

- Die Ergebnisse von typeof helfen nicht immer weiter

    Typ                  Ergebnis von typeof
    object               "object"
    function             "function"
    array                "object"
    number               "number"
    string               "string"
    boolean              "boolean"
    null                 "object"
    undefined            "undefined"

www.assono.de                                    Seite 17
Schleifen

- for (initialisierung; vergleich; inkrement)
  {...}

- alle drei Elemente können durch Komma (!) getrennt
  mehrere Anweisungen enthalten, z. B.
- for (
     var i = 0, result = "";
     i < 100;
     i++, result += i + "n"
  ) {...}




www.assono.de                                   Seite 18
Die with-Falle

- with (obj) {
     member = "Wert";
  }

- wenn obj das Attribut member enthält, wird dieses
  gesetzt

- sonst eine globale Variable namens member!




www.assono.de                                     Seite 19
Falle Semikolon-Einfügung

- Wenn ein Fehler auftritt, versucht der Interpreter es
  noch einmal, nachdem er vor dem nächsten
  Zeilenumbruch ein Semikolon eingefügt hat.
- Beispiel:
  return // hier wird ein Semikolon eingefügt
  { // wird als Block interpretiert
      status: "ok" // status ist ein Label und
                   // Semikolon wird eingefügt
  }; // Block wird nie ausgeführt

- Das kann auch Fehler maskieren.




www.assono.de                                       Seite 20
Referenzen

- Variablen enthalten Referenzen
- Funktionsparameter immer Referenzen, nicht Werte




www.assono.de                                  Seite 21
Funktionen sind Objekte

- Funktionen sind Daten.
- Funktionen können in Variablen gespeichert werden.
- Funktionen können als Argumente übergeben
  werden.
- Funktionen können Attribute und Methoden (also
  innere Funktionen) haben.




www.assono.de                                      Seite 22
Definition von Funktionen

- function f (arg) { ... }
  ist Abkürzung für
  var f = function f(arg) { ... }

- anonyme Funktion
  var f = function (arg) { ... }

- innere Funktion
  function f() {
      ...
      function g() { ... }
      ...
  }

- new Function f(arg, body)

www.assono.de                       Seite 23
Funktionsparameter

- Deklaration enthält Liste der erwarteten Parameter

- Zugriff auf alle Parameter mit arguments, einem
  Array-ähnlichen Konstrukt
- Beispiel:
  function sum() {
      var i, result = 0;
      for (i = 0; i < arguments.length; i++) {
            result += arguments[i];
      }
      return result;
  }
  sum(1, 2, 3, 4, 5);


www.assono.de                                       Seite 24
Funktionsrückgabe

- Funktionen ohne return geben undefined zurück.

- Funktionen mit return x geben x zurück.

- Konstruktoren (später mehr) geben ohne return
  einen Verweis auf das neue Objekt zurück.

- Konstruktoren mit return x geben x zurück, wenn x
  ein Objekt ist, sonst das neue Objekt.




www.assono.de                                     Seite 25
Anonyme Funktionen

- als Parameter für andere Funktionen
   - wenn sie nur dafür gebraucht werden
   - innerhalb der aufgerufenen Funktion haben sie
     dann einen Namen
   - Beispiel: Call-Back-Funktionen bei Ajax-Aufrufen
     bei setTimeout() oder setInterval()
   - setTimeout(
      function(){console.log(new Date());},
      1000
     )




www.assono.de                                      Seite 26
Anonyme Funktionen (forts.)

- zum sofortigen, einmaligen Ausführen
   - z. B. für Initialisierung
   - zum Schutz von lokalen Variablen, die dann nur
     über innere Funktionen zugänglich sind
   - Beispiel:
     function Mensch(name) {
      this.getName = function() {return name};
      this.setName =
             function (newName) {name = newName};
     };
     var me = new Mensch("Thomas");
     me.getName();
    - lokale Variable name nur noch über setName()
      änderbar, also geschützt
www.assono.de                                        Seite 27
„eval is evil“

- Performance
- Sicherheit:
  nur auf vertrauenswürdige Argumente anwenden




www.assono.de                                    Seite 28
alert()

- „Hilfsdebugger“
- blockiert Programmausführung
- Vorsicht bei asynchronen Ajax-Aufrufen




www.assono.de                              Seite 29
Scopes

- nur zwei Arten von Scopes:
   - global
   - Funktion
- insbesondere kein „Block-Scope“, wie z. B. in Java
- Zugriff auf undeklarierte Variable erzeugt neue
  globale Variable (z. B. bei Schreibfehler), aber auch
  function () {
     a = 1;
  }




www.assono.de                                       Seite 30
Scopes (forts.)

- ein unerwarteter Effekt:
  var a = 1;
  function f() {
      alert(a);
      var a = 2;
      alert(a);
  }
  f();

- Ergebnis: undefined (!) und 2

- offenbar 2 Phasen:
   - lokalen Variablen finden und reservieren, dann
   - Block ausführen


www.assono.de                                         Seite 31
Kontext

- jedes Objekt hat eigenen Kontext
- globaler Kontext
- Funktionen haben Zugriff auf Attribute und Methoden
  des Kontexts, in dem sie definiert wurden...
- und weiter „nach oben“ bis zum globalen Kontext.

- Bei Browsern ist das window-Objekt der globale
  Kontext!
- Beispiel:
  a = 1;
  alert(window.a); => 1


www.assono.de                                      Seite 32
Funktionsaufruf

- Funktionen laufen immer in einem Kontext.

- this zeigt immer auf den aktuellen Kontext.

- innere Funktionen können nicht auf this der
  übergeordneten Funktion zugreifen

- Konvention: var that = this;

- 4 Arten, Funktionen aufzurufen:




www.assono.de                                   Seite 33
Funktionsaufruf (forts.)

- Funktionsform f(args):
  f wird ausgeführt im globalen Kontext.

- Methodenform obj.f(args) und obj["f"](args):
  f wird ausgeführt mit obj als Kontext.

- Vorsicht Falle:
  vergisst man das Objekt anzugeben, läuft f im
  globalen Kontext u. U. fehlerfrei durch




www.assono.de                                     Seite 34
Funktionsaufruf (forts.)

- Konstruktor-Form new f(args):
  f läuft im Kontext eines neu erstellten Objekts, das
  auch Rückgabewert der Funktion ist.

- f.apply(obj, args):
  f läuft im Kontext von obj.
  f braucht dazu nicht Methode von obj zu sein!

- Beispiel:
  folgt auf Folie zu Funktionsparametern




www.assono.de                                       Seite 35
Currying

- Man erzeugt zu einer Funktion mit mindestens einem
  Parameter eine neue Funktion mit mindestens einem
  Parameter weniger.
- Beispiel:
  function addGenerator(a) {
      return function(b) {
            return a + b;
      };
  };
  addOne = addGenerator(1);
  var test = addOne(47); // ergibt 48




www.assono.de                                   Seite 36
Closures

- Zugriff auf Attribute und Methoden der
  übergeordneten Funktion bleibt auch nach deren
  Ende erhalten.
- Das nennt man Closure.
- Beispiel:
  tbd.




www.assono.de                                      Seite 37
Objekte

- Objekte sind Mengen von Name-Wert-Paaren
- Namen sind Strings, Werte von beliebigen Typen
- „assoziative Arrays“ oder „Hash Maps“




www.assono.de                                      Seite 38
Erzeugen von Objekten

- Objekt-Literale wie {}
- new
- Object.create(...)




www.assono.de              Seite 39
Objekt-Literale und Zugriff auf Mitglieder

- var obj = {
     vorname : "Thomas",
     "Ort der Geburt": "Gehrden"
  }

- Dann ist obj.vorname gleich "Thomas" und
  obj["Ort der Geburt"] gleich "Gehrden"




www.assono.de                                Seite 40
Konstruktoren

- Funktionen können in Kombination mit new als
  Konstruktor verwendet werden.
- Es wird ein neues, leeres Objekt erzeugt und die
  Funktion in seinem Kontext ausgeführt.

- Vorgabe-Rückgabewert eines Konstruktors ist this,
  also das erzeugte Objekt.




www.assono.de                                        Seite 41
Konstruktoren (forts.)

- Objekte haben das constructor-Attribut, das auf
  ihren Konstruktor zeigt.
- Konvention: Konstruktoren werden groß geschrieben.

- Vorsicht Falle: vergisst man new, wird die Funktion
  einfach im globalen Kontext ausgeführt (kein Fehler)




www.assono.de                                       Seite 42
for ... in-Schleife

- Schleife über alle Attribute und Methoden eines
  Objekts und seiner Vorfahren(!)

- obj.hasOwnProperty("name")




www.assono.de                                       Seite 43
Erweitern von vorhandenen Objekten

- auch von „Produkt“-Objekten, die zur Sprache
  gehören, z. B. Function, Object, String!
- Beispiel:
  String.prototype.trim = function() {
      return this.replace(/^s+|s+$/g, "");
  }
  alert("'" + "    test   ".trim() + "'");




www.assono.de                                    Seite 44
Arrays

- Arrays sind Objekte (erben von Object)

- haben length-Attribut, immer eins größer, als
  größter (Ganzzahl-)Index
- Indexe werden umgewandelt in Strings!

- Array-Literale: ["eins", "zwei", "drei"]

- Strings lassen sich nutzen wie Zeichen-Arrays:
  var text = "abcd"; text[2] => "c"




www.assono.de                                      Seite 45
Die delete-Falle

- delete arr[2]

- löscht das 3. Element,
  genauer: setzt es auf undefined, es bleibt ein Loch:
  arr[2] ist undefined, arr[3] bleibt unverändert

- arr.splice(2, 1)
  entfernt das 3. Element und nachfolgende Elemente
  rücken auf




www.assono.de                                      Seite 46
Funktionsparameter

- Argumente stehen (zusätzlich) in Quasi-Array
  arguments.

- Es gibt arguments.length, aber nicht die anderen
  Array-Methoden.

- Ausweg: Function.prototype.apply()
  function f() {
     var slice = Array.prototype.slice;
     var argsWithoutFirst =
          slice.apply(arguments, [1]);
     ...
  }



www.assono.de                                    Seite 47
Öffentliche Attribute und Methoden (public)

- Grundsätzlich sind alle Properties, also Attribute und
  Methoden eines Objekts öffentlich sichtbar.




www.assono.de                                        Seite 48
Private Attribute und Methoden

- Im Konstruktor definierte Variablen und Funktionen
  werden zu privaten Attributen und Methoden aller
  damit erzeugter Objekte.
- Argumente des Konstruktors werden zu privaten
  Attributen.
- Nur innere Funktionen des Konstruktors können auf
  private Attribute zugreifen.




www.assono.de                                     Seite 49
Priviligierte Methoden

- Priviligierte Methoden sind öffentlich aufrufbar und
  haben gleichzeitig auch Zugriff auf private Attribute
  und Methoden.
- Beispiel:
  obj = {
      var privVariable = "private Variable";
      this.pubMethode = function () {
            alert(privVariable);
      };
  }

- funktionieren über Closures!



www.assono.de                                        Seite 50
„Klassenattribute“

- In Java gibt es den static-Modifier für Klassen-
  Attribute und -Methoden.
- In JavaScript gibt es keine Klassen, aber...
- man kann den Konstruktoren Attribute hinzufügen
  und hat damit fast so etwas wie Klassenattribute.




www.assono.de                                        Seite 51
„Klassenattribute“ (forts.)

- Beispiel (tbd.):
  var obj = {
      anzahlObjekte: 0;
      erzeugeObjekt: function(){
            ++anzahlObjekte;
            ...
      };
      holeAnzahlObjekte: function() {
            return "Es wurden " + anzahlObjekte +
                   " Objekte erzeugt.";
      }
  }




www.assono.de                                Seite 52
Vererbung a la JavaScript

- jedes Objekt hat das prototype-Attribut

- Suchreihenfolge für Attribute und Methoden:
   - aktuelles Objekt a
   - a.prototype
   - a.prototype.prototype
   - usw.
   - bis zuletzt Object.prototype




www.assono.de                                   Seite 53
Prototypische Vererbung

- Attribute und Methoden, die man dem Prototype-
  Objekt hinzufügt, werden „vererbt“ an alle damit
  erstellten Objekte.
- auch lange nach der Erzeugung der Objekte!
- obj.prototype.neueFunktion =
     function () {...};
  obj.neueFunktion(...);

- neueFunktion wird nicht direkt in obj, aber über die
  Prototype-Kette gefunden und dann ausgeführt.




www.assono.de                                        Seite 54
Prototypische Vererbung (forts.)

- Beispiel:
   var Person = function (name) {
       this.name = name;
   };
   Person.prototype.getName = function () {
       return this.name;
   };
   var Benutzer = function(name, passwort) {
       this.name = name;
       this.password = passwort;
   };
   Benutzer.prototype = new Person();
   var ich = new Benutzer("Thomas", "geheim");
   alert("Benutzer " + ich.getName + " erstellt");




www.assono.de                                        Seite 55
Klassische Vererbung nachgebaut

- verschiedene Ansätze, die klassische = klassen-
  basierte Vererbung in JavaScript nachzubauen
   - nach Douglas Crockford
   - nach Markus Nix
   - mit Prototype
   - u.v.a.m.




www.assono.de                                       Seite 56
Klassische Vererbung nach Crockford

- 3 Erweiterungen von Function
   Function.prototype.method = function (name, func) {
      this.prototype[name] = func;
      return this; // nützlich für's Verketten
   };
   Function.method("inherits", function(parent) {
      this.prototype = new parent();
      return this;
   }; // vereinfachte Version ohne uber();
   Function.method("swiss", function (parent) {
      for (var i = 1; i < arguments.lenght; i += 1) {
         var name = arguments[i];
         this.prototype[name] = parent.prototype[name];
      };
      return this;
   };



www.assono.de                                         Seite 57
Klassische Vererbung nach Crockford (forts.)

- Anwendungsbeispiel
   var Person = function(name){this.name = name;};
   Person.method("getName", funtion() {
       return this.name;
   };
   var Benutzer = function(name, passwort) {
       this.name = name;
       this.password = passwort;
   };
   Benutzer.inherits(Person);
   Benutzer.method("getPasswort", function() {
       return this.passwort;
   };




www.assono.de                                        Seite 58
Parasitäre Vererbung

- Rufe im Konstruktor einen anderen Konstruktor auf
  und gebe das von ihm erzeugte Objekt nach
  Erweiterung zurück (statt des neu erzeugten
  Objekts).
- Beispiel:
  function NeuerKonstruktor() {
      var that = VorhandenerKonstruktor();
      that.weitereMethode = function () {...};
      return that; // statt implizit this
  }




www.assono.de                                    Seite 59
Globale Variablen

- Globale Variablen sind böse und zu vermeiden.
- Probleme, wenn z. B. mehrere Bibliotheken die
  gleichen globalen Variablen benutzen.
- unvorhersehbare Ergebnisse




www.assono.de                                     Seite 60
Namespaces

- Namensräume helfen, den globalen Kontext sauber
  zu halten.
- Beispiel:
  var de = {};
  de.assono = {};
  de.assono.HtmlHelper = {
      appendDiv: function(toElement) {...};
      ...
  }




www.assono.de                                  Seite 61
Alternative: Code „verstecken“

- Mit anonymer Funktion kann man Code „verstecken“
- Beispiel:
  (function () {
      var nachricht = "Hallo Welt!";
      window.onload = function () {
            alert(nachricht);
      };
  })(); // Funktion definieren & ausgeführen




www.assono.de                                  Seite 62
Quellen

- Douglas Crockford: „JavaScript: The Good Parts“
- seine Web-Seiten
- „JavaScript Pro Techniques“
- „JavaScript-Überblick“




www.assono.de                                       Seite 63
Fragen?

jetzt stellen – oder später:

    tbahn@assono.de
    http://www.assono.de/blog
    04307/900-401


Folien unter:
http://www.assono.de/blog/d6plinks/
EntwicklerCamp-2010-JavaScript-fuer-Fortgeschrittene




www.assono.de                                   Seite 64

Weitere ähnliche Inhalte

Was ist angesagt? (10)

Metaprogrammierung mit Ruby
Metaprogrammierung mit RubyMetaprogrammierung mit Ruby
Metaprogrammierung mit Ruby
 
Do while
Do whileDo while
Do while
 
Ruby on Rails SS09 03
Ruby on Rails SS09 03Ruby on Rails SS09 03
Ruby on Rails SS09 03
 
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen IBIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I
 
WiSe 2013 | Programmierpraktikum C++ - 05_Strukturierung von Anwendungen
WiSe 2013 | Programmierpraktikum C++ - 05_Strukturierung von AnwendungenWiSe 2013 | Programmierpraktikum C++ - 05_Strukturierung von Anwendungen
WiSe 2013 | Programmierpraktikum C++ - 05_Strukturierung von Anwendungen
 
WiSe 2013 | Programmierpraktikum C++ - 01_Basics
WiSe 2013 | Programmierpraktikum C++ - 01_BasicsWiSe 2013 | Programmierpraktikum C++ - 01_Basics
WiSe 2013 | Programmierpraktikum C++ - 01_Basics
 
Was geht mit Java 17?
Was geht mit Java 17?Was geht mit Java 17?
Was geht mit Java 17?
 
PHP: exit
PHP: exitPHP: exit
PHP: exit
 
An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to Ruby
 
Slides
SlidesSlides
Slides
 

Andere mochten auch

Tabaquismo en Guatemala
Tabaquismo en Guatemala Tabaquismo en Guatemala
Tabaquismo en Guatemala Josué Castro
 
Client Portal: Delivering the Complete Wealth Picture
Client Portal: Delivering the Complete Wealth PictureClient Portal: Delivering the Complete Wealth Picture
Client Portal: Delivering the Complete Wealth PictureSS&C Advent
 
cloud session uklug
cloud session uklugcloud session uklug
cloud session uklugdominion
 
Uklug 2011 administrator development synergy
Uklug 2011 administrator development synergyUklug 2011 administrator development synergy
Uklug 2011 administrator development synergydominion
 
iOS enterprise
iOS enterpriseiOS enterprise
iOS enterprisedominion
 
What is a itil and how does it relate to your collaborative environment uklug
What is a itil and how does it relate to your collaborative environment   uklugWhat is a itil and how does it relate to your collaborative environment   uklug
What is a itil and how does it relate to your collaborative environment uklugdominion
 
JavaScript blast
JavaScript blastJavaScript blast
JavaScript blastdominion
 
Uklug 2011 client management
Uklug 2011 client managementUklug 2011 client management
Uklug 2011 client managementdominion
 

Andere mochten auch (9)

Tabaquismo en Guatemala
Tabaquismo en Guatemala Tabaquismo en Guatemala
Tabaquismo en Guatemala
 
Client Portal: Delivering the Complete Wealth Picture
Client Portal: Delivering the Complete Wealth PictureClient Portal: Delivering the Complete Wealth Picture
Client Portal: Delivering the Complete Wealth Picture
 
Tabaquismo SALUD PUBLICA
Tabaquismo SALUD PUBLICATabaquismo SALUD PUBLICA
Tabaquismo SALUD PUBLICA
 
cloud session uklug
cloud session uklugcloud session uklug
cloud session uklug
 
Uklug 2011 administrator development synergy
Uklug 2011 administrator development synergyUklug 2011 administrator development synergy
Uklug 2011 administrator development synergy
 
iOS enterprise
iOS enterpriseiOS enterprise
iOS enterprise
 
What is a itil and how does it relate to your collaborative environment uklug
What is a itil and how does it relate to your collaborative environment   uklugWhat is a itil and how does it relate to your collaborative environment   uklug
What is a itil and how does it relate to your collaborative environment uklug
 
JavaScript blast
JavaScript blastJavaScript blast
JavaScript blast
 
Uklug 2011 client management
Uklug 2011 client managementUklug 2011 client management
Uklug 2011 client management
 

Mehr von dominion

Populating your domino directory or any domino database with tivoli directory...
Populating your domino directory or any domino database with tivoli directory...Populating your domino directory or any domino database with tivoli directory...
Populating your domino directory or any domino database with tivoli directory...dominion
 
Uklug2011 Know your Notes
Uklug2011 Know your NotesUklug2011 Know your Notes
Uklug2011 Know your Notesdominion
 
Taking themes to the next level
Taking themes to the next levelTaking themes to the next level
Taking themes to the next leveldominion
 
Supersize me
Supersize meSupersize me
Supersize medominion
 
Aussie outback
Aussie outbackAussie outback
Aussie outbackdominion
 
Learning to run
Learning to runLearning to run
Learning to rundominion
 
Implementing xpages extension library
Implementing xpages extension libraryImplementing xpages extension library
Implementing xpages extension librarydominion
 
Abb presentation uklug
Abb presentation uklugAbb presentation uklug
Abb presentation uklugdominion
 
Uklug2011.lotus.on.linux.report.technical.edition.v1.0
Uklug2011.lotus.on.linux.report.technical.edition.v1.0Uklug2011.lotus.on.linux.report.technical.edition.v1.0
Uklug2011.lotus.on.linux.report.technical.edition.v1.0dominion
 
Domino testing presentation
Domino testing presentationDomino testing presentation
Domino testing presentationdominion
 
Composite applications tutorial
Composite applications tutorialComposite applications tutorial
Composite applications tutorialdominion
 
Maximizing application performance
Maximizing application performanceMaximizing application performance
Maximizing application performancedominion
 
Error handling in XPages
Error handling in XPagesError handling in XPages
Error handling in XPagesdominion
 
wcm domino
wcm dominowcm domino
wcm dominodominion
 
leverage dxl
leverage dxlleverage dxl
leverage dxldominion
 
Ajax in domino web-anwendungen - der nächste schritt
Ajax in domino web-anwendungen - der nächste schrittAjax in domino web-anwendungen - der nächste schritt
Ajax in domino web-anwendungen - der nächste schrittdominion
 
lotus notes r851 -training
lotus notes r851 -traininglotus notes r851 -training
lotus notes r851 -trainingdominion
 
Inside notes
Inside notesInside notes
Inside notesdominion
 
Domino security
Domino securityDomino security
Domino securitydominion
 

Mehr von dominion (20)

Populating your domino directory or any domino database with tivoli directory...
Populating your domino directory or any domino database with tivoli directory...Populating your domino directory or any domino database with tivoli directory...
Populating your domino directory or any domino database with tivoli directory...
 
Uklug2011 Know your Notes
Uklug2011 Know your NotesUklug2011 Know your Notes
Uklug2011 Know your Notes
 
Quickr
QuickrQuickr
Quickr
 
Taking themes to the next level
Taking themes to the next levelTaking themes to the next level
Taking themes to the next level
 
Supersize me
Supersize meSupersize me
Supersize me
 
Aussie outback
Aussie outbackAussie outback
Aussie outback
 
Learning to run
Learning to runLearning to run
Learning to run
 
Implementing xpages extension library
Implementing xpages extension libraryImplementing xpages extension library
Implementing xpages extension library
 
Abb presentation uklug
Abb presentation uklugAbb presentation uklug
Abb presentation uklug
 
Uklug2011.lotus.on.linux.report.technical.edition.v1.0
Uklug2011.lotus.on.linux.report.technical.edition.v1.0Uklug2011.lotus.on.linux.report.technical.edition.v1.0
Uklug2011.lotus.on.linux.report.technical.edition.v1.0
 
Domino testing presentation
Domino testing presentationDomino testing presentation
Domino testing presentation
 
Composite applications tutorial
Composite applications tutorialComposite applications tutorial
Composite applications tutorial
 
Maximizing application performance
Maximizing application performanceMaximizing application performance
Maximizing application performance
 
Error handling in XPages
Error handling in XPagesError handling in XPages
Error handling in XPages
 
wcm domino
wcm dominowcm domino
wcm domino
 
leverage dxl
leverage dxlleverage dxl
leverage dxl
 
Ajax in domino web-anwendungen - der nächste schritt
Ajax in domino web-anwendungen - der nächste schrittAjax in domino web-anwendungen - der nächste schritt
Ajax in domino web-anwendungen - der nächste schritt
 
lotus notes r851 -training
lotus notes r851 -traininglotus notes r851 -training
lotus notes r851 -training
 
Inside notes
Inside notesInside notes
Inside notes
 
Domino security
Domino securityDomino security
Domino security
 

T2 s4 javascriptfuerfortgeschrittene

  • 1. EntwicklerCamp 2010 Track 2, Session 4: JavaScript für Fortgeschrittene Gelsenkirchen, 9. März 2010 Innovative Software-Lösungen. www.assono.de
  • 2. Thomas Bahn Diplom-Mathematiker, Universität Hannover seit 1997 entwickle ich mit Java und relationalen Datenbanken seit 1999 mit Notes/Domino zu tun: Entwicklung, Administration, Beratung und Schulungen regelmäßiger Sprecher auf nationalen und internationalen Fachkonferenzen zu IBM Lotus Notes/ Domino und Autor für THE VIEW tbahn@assono.de http://www.assono.de/blog 04307/900-401 www.assono.de Seite 2
  • 3. Variablendeklaration - Variablen-Deklaration: var name; - Variablen-Deklaration kombiniert mit Wertzuweisung: var name = wert; - SSJS-Spezialität: typisierte Variablen-Deklaration: var name : typ = wert; - Prüfung, ob Variable deklariert ist - häufig, aber vereinfacht: if (a) {...} - Vorsicht: der Block wird auch ausgeführt, wenn a gleich false, null, "" oder 0 ist - besser: if (typeof a !== „undefined“) {...} www.assono.de Seite 3
  • 4. Variablentypen - „loose typing“ heißt nicht untypisiert! - Es gibt folgende 6 Typen: - Strings - Numbers - Booleans - Objects - null - undefined www.assono.de Seite 4
  • 5. Spezielle Strings - Maskierungszeichen - ein Rückwärtsstrich - ' ein einfacher Anführungsstrich - " ein doppelter Anführungsstrich - n neue Zeile (newline) - r “Wagenrücklauf“ (carriage return) - t Tabulator - u Unicode-Zeichen, z. B. u042F => Я www.assono.de Seite 5
  • 6. Zahlen - alle Zahlen sind 64-bit Gleitkommazahlen („double“) - Rundungsdifferenzen durch Binär-Dezimal- Konvertierung - Bit-Shifting (<<, >>) möglich, aber kontraproduktiv www.assono.de Seite 6
  • 7. Zahlen (forts.) - 0x Präfix für Hexadezimalzahl-Literale, z. B. 0xFF 0 Präfix für Oktalzahl-Literale, z. B. 014 (=12) - Achtung bei parseInt(), z. B. parseInt(08) => Fehler!, insbesondere bei Benutzereingaben, z. B. beim Monat - daher besser immer bei parseInt() die Basis (radix) als zweiten Parameter mit angeben: parseInt("08", 10); www.assono.de Seite 7
  • 8. Zahlen (forts.) - NaN = Not a Number - „ansteckend“ - ungleich allem anderen (inklusive NaN) - testen mit isNaN() - typeof NaN => "number" www.assono.de Seite 8
  • 9. Zahlen (forts.) - Infinity = unendlich, - z. B. a/0 => Infinity - zumindest größer als die größte gültige Zahl: Infinity > 1.7976931348623157e+308 - -Infinity - ist absolut kleiner als die kleinste gültige Zahl: 5e-324 > -Infinity - beide „ansteckend“ bei Berechnungen, aber - 1/Infinity => 0 - Infinity/Infinity => NaN www.assono.de Seite 9
  • 10. Boolean - ! logisches Nicht - && logisches Und - || logisches Oder - „lazy evaluation“: nur berechnen, wenn noch nötig - Beispiel: var a = 1; true || (a = 2) => a ist noch 1 www.assono.de Seite 10
  • 11. „Falsche“ Werte - Folgende Werte sind „falsch“ (falsy): - false - null („leer“, bewusst gesetzt) - undefined (uninitialisiert oder nicht vorhanden) - "" (leere Zeichenkette) - 0 - NaN - Alle anderen Werte sind true, auch - "0" - "false" www.assono.de Seite 11
  • 12. Vergleiche - == Gleichheit ggf. nach Typumwandlung - != Ungleichheit ggf. nach Typumwandlung - === Gleichheit ohne Typumwandlung - !== Ungleichheit ohne Typumwandlung - Beispiele - "1" == 1 ist wahr - "1" === 1 ist falsch www.assono.de Seite 12
  • 13. Vergleiche (forts.) - switch - Vergleich ohne Typumwandlung - a ? b : c - ternärer Operator - wenn a wahr ergibt, ist das Ergebnis b, sonst c www.assono.de Seite 13
  • 14. Guard-Operator: && - && ist logisches Und - Beispiel: return obj && obj.member; - gibt obj.member zurück, wenn obj nicht undefined oder null ist (oder präziser: nicht false ist) - aber Vorsicht, wenn false, null, "", 0 gültige Werte sein können! www.assono.de Seite 14
  • 15. Default-Operator: || - || ist logisches Oder - Beispiel var value = arg || "Vorgabewert"; - wenn arg nicht „falsch“ ist, wird value arg zugewiesen, sonst "Vorgabewert" - aber Vorsicht, wenn false, null, "", 0 gültige Werte sein können! - nützlich bei optionalen Parametern einer Funktion www.assono.de Seite 15
  • 16. Noch mehr Operator-Magie - + als unärer Operator wandelt Strings um in Zahlen: +"1" === 1 - !! wandelt um in Boolean: !!"1" === true www.assono.de Seite 16
  • 17. typeof-Operator - Die Ergebnisse von typeof helfen nicht immer weiter Typ Ergebnis von typeof object "object" function "function" array "object" number "number" string "string" boolean "boolean" null "object" undefined "undefined" www.assono.de Seite 17
  • 18. Schleifen - for (initialisierung; vergleich; inkrement) {...} - alle drei Elemente können durch Komma (!) getrennt mehrere Anweisungen enthalten, z. B. - for ( var i = 0, result = ""; i < 100; i++, result += i + "n" ) {...} www.assono.de Seite 18
  • 19. Die with-Falle - with (obj) { member = "Wert"; } - wenn obj das Attribut member enthält, wird dieses gesetzt - sonst eine globale Variable namens member! www.assono.de Seite 19
  • 20. Falle Semikolon-Einfügung - Wenn ein Fehler auftritt, versucht der Interpreter es noch einmal, nachdem er vor dem nächsten Zeilenumbruch ein Semikolon eingefügt hat. - Beispiel: return // hier wird ein Semikolon eingefügt { // wird als Block interpretiert status: "ok" // status ist ein Label und // Semikolon wird eingefügt }; // Block wird nie ausgeführt - Das kann auch Fehler maskieren. www.assono.de Seite 20
  • 21. Referenzen - Variablen enthalten Referenzen - Funktionsparameter immer Referenzen, nicht Werte www.assono.de Seite 21
  • 22. Funktionen sind Objekte - Funktionen sind Daten. - Funktionen können in Variablen gespeichert werden. - Funktionen können als Argumente übergeben werden. - Funktionen können Attribute und Methoden (also innere Funktionen) haben. www.assono.de Seite 22
  • 23. Definition von Funktionen - function f (arg) { ... } ist Abkürzung für var f = function f(arg) { ... } - anonyme Funktion var f = function (arg) { ... } - innere Funktion function f() { ... function g() { ... } ... } - new Function f(arg, body) www.assono.de Seite 23
  • 24. Funktionsparameter - Deklaration enthält Liste der erwarteten Parameter - Zugriff auf alle Parameter mit arguments, einem Array-ähnlichen Konstrukt - Beispiel: function sum() { var i, result = 0; for (i = 0; i < arguments.length; i++) { result += arguments[i]; } return result; } sum(1, 2, 3, 4, 5); www.assono.de Seite 24
  • 25. Funktionsrückgabe - Funktionen ohne return geben undefined zurück. - Funktionen mit return x geben x zurück. - Konstruktoren (später mehr) geben ohne return einen Verweis auf das neue Objekt zurück. - Konstruktoren mit return x geben x zurück, wenn x ein Objekt ist, sonst das neue Objekt. www.assono.de Seite 25
  • 26. Anonyme Funktionen - als Parameter für andere Funktionen - wenn sie nur dafür gebraucht werden - innerhalb der aufgerufenen Funktion haben sie dann einen Namen - Beispiel: Call-Back-Funktionen bei Ajax-Aufrufen bei setTimeout() oder setInterval() - setTimeout( function(){console.log(new Date());}, 1000 ) www.assono.de Seite 26
  • 27. Anonyme Funktionen (forts.) - zum sofortigen, einmaligen Ausführen - z. B. für Initialisierung - zum Schutz von lokalen Variablen, die dann nur über innere Funktionen zugänglich sind - Beispiel: function Mensch(name) { this.getName = function() {return name}; this.setName = function (newName) {name = newName}; }; var me = new Mensch("Thomas"); me.getName(); - lokale Variable name nur noch über setName() änderbar, also geschützt www.assono.de Seite 27
  • 28. „eval is evil“ - Performance - Sicherheit: nur auf vertrauenswürdige Argumente anwenden www.assono.de Seite 28
  • 29. alert() - „Hilfsdebugger“ - blockiert Programmausführung - Vorsicht bei asynchronen Ajax-Aufrufen www.assono.de Seite 29
  • 30. Scopes - nur zwei Arten von Scopes: - global - Funktion - insbesondere kein „Block-Scope“, wie z. B. in Java - Zugriff auf undeklarierte Variable erzeugt neue globale Variable (z. B. bei Schreibfehler), aber auch function () { a = 1; } www.assono.de Seite 30
  • 31. Scopes (forts.) - ein unerwarteter Effekt: var a = 1; function f() { alert(a); var a = 2; alert(a); } f(); - Ergebnis: undefined (!) und 2 - offenbar 2 Phasen: - lokalen Variablen finden und reservieren, dann - Block ausführen www.assono.de Seite 31
  • 32. Kontext - jedes Objekt hat eigenen Kontext - globaler Kontext - Funktionen haben Zugriff auf Attribute und Methoden des Kontexts, in dem sie definiert wurden... - und weiter „nach oben“ bis zum globalen Kontext. - Bei Browsern ist das window-Objekt der globale Kontext! - Beispiel: a = 1; alert(window.a); => 1 www.assono.de Seite 32
  • 33. Funktionsaufruf - Funktionen laufen immer in einem Kontext. - this zeigt immer auf den aktuellen Kontext. - innere Funktionen können nicht auf this der übergeordneten Funktion zugreifen - Konvention: var that = this; - 4 Arten, Funktionen aufzurufen: www.assono.de Seite 33
  • 34. Funktionsaufruf (forts.) - Funktionsform f(args): f wird ausgeführt im globalen Kontext. - Methodenform obj.f(args) und obj["f"](args): f wird ausgeführt mit obj als Kontext. - Vorsicht Falle: vergisst man das Objekt anzugeben, läuft f im globalen Kontext u. U. fehlerfrei durch www.assono.de Seite 34
  • 35. Funktionsaufruf (forts.) - Konstruktor-Form new f(args): f läuft im Kontext eines neu erstellten Objekts, das auch Rückgabewert der Funktion ist. - f.apply(obj, args): f läuft im Kontext von obj. f braucht dazu nicht Methode von obj zu sein! - Beispiel: folgt auf Folie zu Funktionsparametern www.assono.de Seite 35
  • 36. Currying - Man erzeugt zu einer Funktion mit mindestens einem Parameter eine neue Funktion mit mindestens einem Parameter weniger. - Beispiel: function addGenerator(a) { return function(b) { return a + b; }; }; addOne = addGenerator(1); var test = addOne(47); // ergibt 48 www.assono.de Seite 36
  • 37. Closures - Zugriff auf Attribute und Methoden der übergeordneten Funktion bleibt auch nach deren Ende erhalten. - Das nennt man Closure. - Beispiel: tbd. www.assono.de Seite 37
  • 38. Objekte - Objekte sind Mengen von Name-Wert-Paaren - Namen sind Strings, Werte von beliebigen Typen - „assoziative Arrays“ oder „Hash Maps“ www.assono.de Seite 38
  • 39. Erzeugen von Objekten - Objekt-Literale wie {} - new - Object.create(...) www.assono.de Seite 39
  • 40. Objekt-Literale und Zugriff auf Mitglieder - var obj = { vorname : "Thomas", "Ort der Geburt": "Gehrden" } - Dann ist obj.vorname gleich "Thomas" und obj["Ort der Geburt"] gleich "Gehrden" www.assono.de Seite 40
  • 41. Konstruktoren - Funktionen können in Kombination mit new als Konstruktor verwendet werden. - Es wird ein neues, leeres Objekt erzeugt und die Funktion in seinem Kontext ausgeführt. - Vorgabe-Rückgabewert eines Konstruktors ist this, also das erzeugte Objekt. www.assono.de Seite 41
  • 42. Konstruktoren (forts.) - Objekte haben das constructor-Attribut, das auf ihren Konstruktor zeigt. - Konvention: Konstruktoren werden groß geschrieben. - Vorsicht Falle: vergisst man new, wird die Funktion einfach im globalen Kontext ausgeführt (kein Fehler) www.assono.de Seite 42
  • 43. for ... in-Schleife - Schleife über alle Attribute und Methoden eines Objekts und seiner Vorfahren(!) - obj.hasOwnProperty("name") www.assono.de Seite 43
  • 44. Erweitern von vorhandenen Objekten - auch von „Produkt“-Objekten, die zur Sprache gehören, z. B. Function, Object, String! - Beispiel: String.prototype.trim = function() { return this.replace(/^s+|s+$/g, ""); } alert("'" + " test ".trim() + "'"); www.assono.de Seite 44
  • 45. Arrays - Arrays sind Objekte (erben von Object) - haben length-Attribut, immer eins größer, als größter (Ganzzahl-)Index - Indexe werden umgewandelt in Strings! - Array-Literale: ["eins", "zwei", "drei"] - Strings lassen sich nutzen wie Zeichen-Arrays: var text = "abcd"; text[2] => "c" www.assono.de Seite 45
  • 46. Die delete-Falle - delete arr[2] - löscht das 3. Element, genauer: setzt es auf undefined, es bleibt ein Loch: arr[2] ist undefined, arr[3] bleibt unverändert - arr.splice(2, 1) entfernt das 3. Element und nachfolgende Elemente rücken auf www.assono.de Seite 46
  • 47. Funktionsparameter - Argumente stehen (zusätzlich) in Quasi-Array arguments. - Es gibt arguments.length, aber nicht die anderen Array-Methoden. - Ausweg: Function.prototype.apply() function f() { var slice = Array.prototype.slice; var argsWithoutFirst = slice.apply(arguments, [1]); ... } www.assono.de Seite 47
  • 48. Öffentliche Attribute und Methoden (public) - Grundsätzlich sind alle Properties, also Attribute und Methoden eines Objekts öffentlich sichtbar. www.assono.de Seite 48
  • 49. Private Attribute und Methoden - Im Konstruktor definierte Variablen und Funktionen werden zu privaten Attributen und Methoden aller damit erzeugter Objekte. - Argumente des Konstruktors werden zu privaten Attributen. - Nur innere Funktionen des Konstruktors können auf private Attribute zugreifen. www.assono.de Seite 49
  • 50. Priviligierte Methoden - Priviligierte Methoden sind öffentlich aufrufbar und haben gleichzeitig auch Zugriff auf private Attribute und Methoden. - Beispiel: obj = { var privVariable = "private Variable"; this.pubMethode = function () { alert(privVariable); }; } - funktionieren über Closures! www.assono.de Seite 50
  • 51. „Klassenattribute“ - In Java gibt es den static-Modifier für Klassen- Attribute und -Methoden. - In JavaScript gibt es keine Klassen, aber... - man kann den Konstruktoren Attribute hinzufügen und hat damit fast so etwas wie Klassenattribute. www.assono.de Seite 51
  • 52. „Klassenattribute“ (forts.) - Beispiel (tbd.): var obj = { anzahlObjekte: 0; erzeugeObjekt: function(){ ++anzahlObjekte; ... }; holeAnzahlObjekte: function() { return "Es wurden " + anzahlObjekte + " Objekte erzeugt."; } } www.assono.de Seite 52
  • 53. Vererbung a la JavaScript - jedes Objekt hat das prototype-Attribut - Suchreihenfolge für Attribute und Methoden: - aktuelles Objekt a - a.prototype - a.prototype.prototype - usw. - bis zuletzt Object.prototype www.assono.de Seite 53
  • 54. Prototypische Vererbung - Attribute und Methoden, die man dem Prototype- Objekt hinzufügt, werden „vererbt“ an alle damit erstellten Objekte. - auch lange nach der Erzeugung der Objekte! - obj.prototype.neueFunktion = function () {...}; obj.neueFunktion(...); - neueFunktion wird nicht direkt in obj, aber über die Prototype-Kette gefunden und dann ausgeführt. www.assono.de Seite 54
  • 55. Prototypische Vererbung (forts.) - Beispiel: var Person = function (name) { this.name = name; }; Person.prototype.getName = function () { return this.name; }; var Benutzer = function(name, passwort) { this.name = name; this.password = passwort; }; Benutzer.prototype = new Person(); var ich = new Benutzer("Thomas", "geheim"); alert("Benutzer " + ich.getName + " erstellt"); www.assono.de Seite 55
  • 56. Klassische Vererbung nachgebaut - verschiedene Ansätze, die klassische = klassen- basierte Vererbung in JavaScript nachzubauen - nach Douglas Crockford - nach Markus Nix - mit Prototype - u.v.a.m. www.assono.de Seite 56
  • 57. Klassische Vererbung nach Crockford - 3 Erweiterungen von Function Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; // nützlich für's Verketten }; Function.method("inherits", function(parent) { this.prototype = new parent(); return this; }; // vereinfachte Version ohne uber(); Function.method("swiss", function (parent) { for (var i = 1; i < arguments.lenght; i += 1) { var name = arguments[i]; this.prototype[name] = parent.prototype[name]; }; return this; }; www.assono.de Seite 57
  • 58. Klassische Vererbung nach Crockford (forts.) - Anwendungsbeispiel var Person = function(name){this.name = name;}; Person.method("getName", funtion() { return this.name; }; var Benutzer = function(name, passwort) { this.name = name; this.password = passwort; }; Benutzer.inherits(Person); Benutzer.method("getPasswort", function() { return this.passwort; }; www.assono.de Seite 58
  • 59. Parasitäre Vererbung - Rufe im Konstruktor einen anderen Konstruktor auf und gebe das von ihm erzeugte Objekt nach Erweiterung zurück (statt des neu erzeugten Objekts). - Beispiel: function NeuerKonstruktor() { var that = VorhandenerKonstruktor(); that.weitereMethode = function () {...}; return that; // statt implizit this } www.assono.de Seite 59
  • 60. Globale Variablen - Globale Variablen sind böse und zu vermeiden. - Probleme, wenn z. B. mehrere Bibliotheken die gleichen globalen Variablen benutzen. - unvorhersehbare Ergebnisse www.assono.de Seite 60
  • 61. Namespaces - Namensräume helfen, den globalen Kontext sauber zu halten. - Beispiel: var de = {}; de.assono = {}; de.assono.HtmlHelper = { appendDiv: function(toElement) {...}; ... } www.assono.de Seite 61
  • 62. Alternative: Code „verstecken“ - Mit anonymer Funktion kann man Code „verstecken“ - Beispiel: (function () { var nachricht = "Hallo Welt!"; window.onload = function () { alert(nachricht); }; })(); // Funktion definieren & ausgeführen www.assono.de Seite 62
  • 63. Quellen - Douglas Crockford: „JavaScript: The Good Parts“ - seine Web-Seiten - „JavaScript Pro Techniques“ - „JavaScript-Überblick“ www.assono.de Seite 63
  • 64. Fragen? jetzt stellen – oder später: tbahn@assono.de http://www.assono.de/blog 04307/900-401 Folien unter: http://www.assono.de/blog/d6plinks/ EntwicklerCamp-2010-JavaScript-fuer-Fortgeschrittene www.assono.de Seite 64