Präsentation zum Thema "Powerful mostly unknown Javascript-Features", gehalten von Entwicklern der Softwareagentur App Aware: Sascha Hameister und Aron Homberg
2. Sascha Hameister
- lebt in Berlin
- Entwickler, App Aware
- über 10 Jahre Entwicklungserfahrung
- Speaker auf Fachkonferenzen
- Autor bei O‘Reilly und Hanser-Verlag
- Fokus: Mobile, Web
2
Freitag, 20. November 2009 2
3. Aron Homberg
- lebt in München
- Entwickler, App Aware
- über 8 Jahre Entwicklungserfahrung
- Speaker auf Fachkonferenzen
- Autor bei O‘Reilly und Hanser-Verlag
- Aktiv in der OpenSource Gemeinschaft
- Fokus: Web, Datenbanken
3
Freitag, 20. November 2009 3
4. Agenda
- Daten über mehrere Aufrufe persistent halten
- Anonyme Funktionen verwenden
- Debugging von Objekten verbessern
- Standard-Verhalten nativer Funktionen ersetzen
- Aufrufhierarchien ohne Temporärvariablen
- Funktionen mit beliebiger Argumentanzahl
- Funktionalität bestehender Funktionen dynamisch erweitern
- Folgefehler durch Objektreferenzierung verhindern
- Keywords
4
Freitag, 20. November 2009 4
5. Daten über mehrere Aufrufe
persistent halten
5
Freitag, 20. November 2009 5
6. Daten über mehrere Aufrufe
persistent halten
- Gründe
- Persistenz im Client abbilden
- Netzwerktraffic verringern
- Serverlast verringern
6
Freitag, 20. November 2009 6
8. Client Cookies
- Die Anatomie eines Cookies:
cookieName=cookieValue
- Weitere Parameter:
- Expire date (Default: Zum Ende der Zugriffsphase)
- Path (Default: Aufrufendes Dokument)
- Domain (Default: Aktuelle Domain)
- Secure (Boolscher Parameter: Wird eine verschlüsselte
Verbindung benötigt? (HTTPS)
8
Freitag, 20. November 2009 8
9. Client Cookies
- Setzen eines lokalen Cookies:
document.cookie = "dieAntwort=42";
- Das ganze einfach testen:
alert(document.cookie);
// Besser (mit Firebug)
⋮
>>> console.debug(document.cookie);
dieAntwort=42; ... (weitere Cookies)
9
Freitag, 20. November 2009 9
10. Client Cookies
- Eine schöne Funktion zum speichern:
function setCookie(name, value, expires, path, domain, secure) {
var curCookie = name + "=" + escape(value) +
((expires) ? "; expires=" + expires.toGMTString() : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
((secure) ? "; secure" : "");
document.cookie = curCookie;
}
- Persistenz bis zur nächsten WebTechCon:
var naechsteWTC = new Date();
naechsteWTC.setTime(naechsteWTC.getTime() +
365 * 24 * 60 * 60 * 1000);
setCookie("dieAntwort", 42, naechsteWTC);
Freitag, 20. November 2009 10
11. Client Cookies
- Und das ganze auslesen:
function getCookie(name) {
var dc = document.cookie;
var prefix = name + "=";
var begin = dc.indexOf("; " + prefix);
if (begin == -1) {
begin = dc.indexOf(prefix);
if (begin != 0) return null;
} else
begin += 2;
var end = document.cookie.indexOf(";", begin);
if (end == -1)
end = dc.length;
return unescape(dc.substring(begin + prefix.length, end));
}
- Achtung: Cookies werden escaped gespeichert und müssen daher
durch get/setCookie un/escaped werden.
Freitag, 20. November 2009 11
12. Client Cookies
- Die Persistenzschicht ist fertig:
console.log(getCookie("dieAntwort"));
⋮
42
- Seite neu laden... und das ganze nochmal:
getCookie("dieAntwort")
-> 42 :-)
- Implementiert z.B. im Dojo-Framework im Namespace:
dojo.cookie
Freitag, 20. November 2009 12
20. Debugging von Objekten
verbessern
- Gründe
- Standard-Debugging-Output von Objekten ist stets
[object Object]
- Objekte werden serialisierbar (beispielsweise für den Versand
zum Server)
function Person (firstName, lastName) {
}
var p = new Person("Sascha", "Hameister");
alert(p); // [object Object]
alert(p + " FOO"); // [object Object] FOO
20
Freitag, 20. November 2009 20
26. Native function overloading
var _alert = window.alert;
function alert(msg) {
console.debug(msg);
}
alert("FOO"); // Debugs FOO
_alert("BAR") // Alerts BAR with native alert-window.
delete window.alert; // Später dazu mehr :)
alert("FOO AGAIN!");
26
Freitag, 20. November 2009 26
28. Aufrufhierarchien ohne
Temporärvariablen
- Gründe
- Mehrstu ge Aufrufverkettungen gut leserlich implementieren
(beispielsweise bei Graphenzeichnung oder Charting)
28
Freitag, 20. November 2009 28
30. Chaining
- Verkettete Funktionsaufrufe de nieren:
var validValues = new Array(
{valid: false, value: 0},
{valid: true, value: 1}
).filter(function(ele) {
if (ele.valid) {return ele}
}).map(function(ele) {
return ele.value;
}).toString();
console.log(validValues); // -> 1
30
Freitag, 20. November 2009 30
31. Chaining
- Pro‘s:
- Sehr gut anwendbar, um temporäre Variablen zu vermeiden
- Kann bei kleinen Chains die Lesbarkeit erhöhen
- Automatisches „delete“ der - implizit nicht deklarierten -
Temporärvariablen (Speicherschonend, weniger Code!)
- Con‘s:
- Achtung bei „unde ned“ returns!
- Achtung bei zu langen Verkettungen! (Lesbarkeit)
31
Freitag, 20. November 2009 31
33. Funktionen mit beliebiger
Argumentanzahl
- Gründe
- Realisierung von Funktionen wie printf
- Realisierung von Funktionen ohne benamte Parameter
33
Freitag, 20. November 2009 33
35. arguments
- Beliebige Argumentanzahlen verarbeiten:
function lotOfArgs()
{
console.debug(arguments);
}
lotOfArgs("A", "B", 3, 4, 20, true, /rg/);
⋮
-> ["A", "B", 3, 4, 20, true, /rg/]
- „arguments“ ist ein Keyword im Funktionskontext
- Es ist als Array iterierbar (arguments.length, arguments[i])
35
Freitag, 20. November 2009 35
36. arguments
- Tracing des Aufrufers & Dynamische Rekursion:
var maxThiefTry = 3;
function thief() {
attractOfficer();
}
function attractOfficer() {
maxThiefTry--;
console.log("Arrest thief in... " + maxThiefTry + "times!");
if (maxThiefTry > 0) {
arguments.callee();
} else {
console.log("Thief arrested!")
}
}
thief();
- arguments.callee references calling function and scope36
Freitag, 20. November 2009 36
37. arguments
- Drei Chancen hatte er ;-)
Arrest thief in... 2times!
Arrest thief in... 1times!
Arrest thief in... 0times!
Thief arrested!
- Die Aufgerufene Funktion ruft den Aufrufer dynamisch auf und
muss nichts über dessen Funktionsnamen etc. wissen.
- Es lassen sich so endliche und unendliche dynamische
Rekursionsschleifen bzw. Ping-Pongs erstellen.
37
Freitag, 20. November 2009 37
39. Funktionalität bestehender
Funktionen dynamisch erweitern
- Gründe
- Bestehende Funktionen nicht weiter aufblähen
- Mixen mehrerer Funktionalitäten zu einer neuen Funktion
39
Freitag, 20. November 2009 39
41. Delegation
- Funktionen miteinander vereinen (Mixing)
function delegate() {
var stack = arguments;
return function() {
for (var i=0; i<stack.length; i++) {
stack[i](arguments);
}
};
}
var func1 = function() {console.debug(arguments)};
var func2 = function() {console.debug(arguments)};
func3 = delegate(func1, func2);
func3("C");
- „func3()“ ruft „func1()“ und „func2()“ mit seinen
Aufrufparametern auf! 41
Freitag, 20. November 2009 41
42. Folgefehler durch
Objektreferenzierung verhindern
42
Freitag, 20. November 2009 42
43. Folgefehler durch
Objektreferenzierung verhindern
- Standard: Mit Referenzen arbeiten:
var aron = {name: "Aron Homberg"};
var sascha = aron;
sascha.name = "Sascha Hameister";
console.debug(aron);
-> aron.name -> „Sascha Hameister“
- Achtung: Versteckte Bugs!
Durch die Verwendung als Referenz wurde das Objekt Aron
ebenfalls manipuliert!
- Skalare Typen werden immer kopiert, nie referenziert.
43
Freitag, 20. November 2009 43
45. Objekte klonen
- Lösung: Objekte und ihre Attribute (1st-Level) klonen!
function clone(props) {
var tobj = {};
for(var x in props){
tobj[x] = props[x];
}
return tobj;
}
var aron = {name: "Aron Homberg"};
var sascha = clone(aron);
sascha.name = "Sascha Hameister";
console.debug(aron);
-> aron.name -> „Aron Homberg“ // Bleibt unverändert!
- Diese Funktion klont lediglich die erste Attribut-Ebene eines
Objekts. In tieferen Ebenen blieben Referenzen erhalten.
Freitag, 20. November 2009 45
49. Keyword: instanceof
- Gibt true zurück, wenn das Objekt die Instanz einer gegebenen
Klasse ist.
var example = 'FOO';
alert(example instanceof String); // false
var example = new String('FOO');
alert(example instanceof String); // true
49
Freitag, 20. November 2009 49
51. Keyword: typeof
var example = 'FOO';
alert(typeof example); // string
var example = 10;
alert(typeof example); // number
var example = true;
alert(typeof example); // boolean
var example = /foo/ig
alert(typeof example); // object
var example = [];
alert(typeof example); // object
var example = {};
alert(typeof example); // object
51
Freitag, 20. November 2009 51
55. Keyword: delete
- Per delete können Zuweisungen aller Art hart gelöscht werden:
var object = {
attribute1 : 'value1',
attribute2 : 'value2'
};
⋮
delete object.attribute1;
Mit „delete“ lässt sich Speicher freiräumen. Temporärvariablen bei
Iterationen sollten so immer „Garbage collected“ werden.
55
Freitag, 20. November 2009 55
56. Keyword: delete
- Aufpassen bei Arrays oder Iterationen!
var anArray = ['foo', 'bar'];
delete anArray[1];
for (var i = 0; i < anArray.length; i++) {
console.log(anArray[i]); // foo, undefined
}
Es wird hart gelöscht. Eine Änderung der Indizes oder des length-
Attributes des Arrays erfolgt nicht!
56
Freitag, 20. November 2009 56
57. Keyword: delete
- ACHTUNG: delete() löscht je nach Implementation (Javascript-
VM / Interpreter) hart die Referenz aus dem Memory.
- Bei Zugriff auf einen so gelöschten Wert können dadurch
kritische Interpreter / VM-Runtime Execution Fehler auftreten.
57
Freitag, 20. November 2009 57
59. Keyword: in
var object = {
attribute1 : 'value1',
attribute2 : 'value2'
};
'attribute1' in object // TRUE
var object = {
attribute1 : 'value1',
attribute2 : 'value2'
};
var idx;
for (idx in object) {
alert(object[idx]); // two alerts… value1, value2
}
59
Freitag, 20. November 2009 59
60. Keyword: in (Prototypes!)
Object.prototype.example = function () {};
var object = {
attribute1 : 'value1',
attribute2 : 'value2'
};
var idx;
for (idx in object) {
alert(object[idx]); // Was erwarten Sie?
}
value1
value2
function () {}
60
Freitag, 20. November 2009 60
61. Keyword: in (Prototypes!)
- Bei der Nutzung von in bei jedem Cycle Plausibilitätsprüfung
des aktuellen Typs
Object.prototype.example = function () {};
var object = {
attribute1 : 'value1',
attribute2 : 'value2'
};
var currentObject;
var idx;
for (idx in object) {
currentObject = object[idx];
if (typeof currentObject === 'string') {
alert(object[idx]); // two alerts… value1, value2
}
} 61
Freitag, 20. November 2009 61
65. Keyword: new
function MyClass () {}
var foo = new MyClass();
var bar = MyClass();
// Unterschied?
function MyClass () {
if (!(this instanceof MyClass)) {
throw 'You tried to instantiate MyClass without new.';
}
}
65
Freitag, 20. November 2009 65