Monthly Archives: March 2013

Was macht das “new” Keyword in JavaScript?

new Keyword JavaScriptIn meinem Post zum Versuch soetwas wie Klassen in JavaScript zu ermöglichen, hatte ich geschrieben, dass “new” in JavaScript irreführend ist. Nehmen wir folgendes Beispiel:

function Example( a ) { this.a = 2 }
Example.prototype = {
  a: 1,
  b: function() { console.log(this.a); }
};

var test = new Example();
test.b();

“New” kann man eigentlich als Funktion betrachten und was in dieser, quasi hinter den Kulissen, passiert ist folgendes:

  1. Erstelle ein neues (JavaScript-)Objekt
  2. Setze den Typ des neuen Objektes auf “Object
  3. Setze die Eigenschaften (Properties) des Prototyp-Objekts als die Eigenschaften des Prototypes des neu erstellten Objekts.
  4. Führe die Funktion Example aus. Übergebe dieser Funktion hierfür das neu erstellte Objekt als “this” und sofern vorhanden übergebe die restlichen Parameter.
  5. Gebe das erstellte Objekt zurück.

Als Code sieht das dann in etwa so aus:

function new( func ) {
  var NewObject = {};
  NewObject.__proto__ = func.prototype;
  func.apply(NewObject, func.arguments);
  return NewObject;
}

function Example( a ) { this.a = 2 }
Example.prototype = {
  a: 1,
  b: function() { console.log(this.a); }
};

var test = new(Example());
test.b();

Das Beispiel ist sehr flach gehalten und soll wirklich nur der groben Veranschaulichung dienen. Genau nachlesen könnt ihr die Ausführung von “new” hier:

“New” ist also eher eine Art Kopiervorgang gepaart mit der Ausführung einer (Initial-)Funktion. Es ist somit nicht zu verwechseln mit dem “new” in Java oder ähnlichen Sprachen. Was ich in dem Zusammenhang mit irreführend meine ist, dass das “new” in JavaScript eigentlich eingeführt wurde, damit sich Java- und andere Entwickler wohler fühlen, es aber eigentlich etwas ganz anderes macht, als es ein Java-Entwickler erwartet.

Wenn ich in diesem Artikel von Prototyp sprach, meinte ich immer den Function-Prototype in JavaScript. Natürlich ist es nicht möglich eine Funktion “new” zu bennen, das Wort ist reserviert und dient im Beispiel nur der Veranschaulichung.

JavaScript Closures leicht und klar erklärt

Mit der Kategorie “LUKE” – “leicht und klar erklärt” möchte ich eine neue Serie starten, in der ich einige Dinge beschreibe / erkläre. Im Gegensatz zu den meisten online Ressourcen werde ich es aber immer möglichst leicht halten und möchte klar und eingehend erklären, was Sache ist. Man könnte sagen, ich versuche es mit dem Wortschatz eines Anfängers und nicht mit dem eines Profis zu erklären. Wörter, die eventuell trotzdem unklar sein könnten, versuche ich möglichst immer mit einem Link zu hinterlegen, der diesen Begriff dann näher erklärt. Häufig findet man hinter Begriffen in Klammern “()” auch den Fachbegriff.

Als Eröffnungsthema der Kategorie nehme ich die Closures. Ein Closure (engl. Abschluss) ist in JavaScript ein Rückgabewert einer Funktion. Dieser Rückgabewert wiederum ist auch eine Funktion. Ein Closure ist also eine Funktion, die von einer Funktion zurückgegeben wird. Das besondere an dieser Funktion ist, dass sie quasi die Zeit einfrieren kann. Sie merkt sich ihre Umgebung (Context) zum Erstellungszeitpunkt und kann auf diese später wieder zugreifen, obwohl die Umgebung eigentlich nicht mehr existiert.  Wenn eine Funktion ihr Ende erreicht hat wird alles von ihr bekannte durch den Müllsammler (Garbage Collector) weggeräumt. Seht euch folgendes Beispiel an:

var noClosure = function () {
    var a = a || 1;
    var b = b || 2;
    b = b + 1;
    return a + b;
}
console.log(noClosure());
console.log(noClosure());
console.log(noClosure());
console.log(noClosure());
 
= 4
= 4
= 4
= 4

Wenn die Funktion “noClosure” aufgerufen wurde, gibt sie am Ende das Ergebnis von “a + b” zurück. Nachdem sie das getan hat, existieren die Variablen im Programm nicht mehr, weil Sie für den Müllsammler freigegeben wurden.* So können wir also auch nie wieder auf einen Wert, der in der Funktion lebte zurückgreifen. Die Variablen “a” und “b” müssen immer neu belegt werden, da der return aus “a + b” sonst schief gehen würde. Im Context existieren a und b somit nicht. Würde der Inhalt der Funktion noch existieren, würde durch “a || 1″ a zu a zugewiesen und nicht 1.**

Schauen wir uns dagegen folgendes an:

var closure = (function() {
    var a = 1;
    var b = 2;
 
    return function () {
        b = b + 1;
        return a + b;
    }
})();
console.log(closure());
console.log(closure());
console.log(closure());
console.log(closure());
 
= 4
= 5
= 6
= 7

Hier wird der Inhalt nicht jedes mal neu erstellt. Die Variable “b” hat nach jedem Aufruf einen um 1 erhöhten Wert zugewiesen. Wir konservieren also die Werte der Variable “a” und “b” anstelle sie jedes mal neu zu erstellen.

Closures sind ne tolle Sache, damit kann man vieles wirklich wirklich gutes und nützliches machen. Zum Beispiel Caching, Module-Patterns, private Werte usw. Ich bin mir abschließend aber noch nicht ganz sicher, ob man in JS wirklich soetwas wie “private” benötigt.

* Der Garbage Collector sammelt alle Dinge auf (und gibt den davon belegten Speicher wieder frei), die nicht mehr zu erreichen sind. Nicht mehr zu erreichen sind sie, wenn sie außerhalb der Sichtweite / des Anwendungsbereichs (Scope) sind.

** Der || Operator gibt den linken Wert zurück, wenn dieser truthy ist, also zum Beispiel NICHT false, undefined, null. Aufgrund des Hoistings existiert a nie in dieser Methode. Wäre die Methode aber konserviert, würde nicht jedes mal der Kontext zurück gesetzt werden, ein Hoisting müsste ebenfalls nicht stattfinden und a würde somit existieren.

JSONP – Eine Methode um die Same-Origin-Policy zu umgehen

Die Same-Origin-Policy untersagt clientseitigen Skriptsprachen wie JavaScript Anfragen an Server zu stellen, die nicht der gleichen Herkunft / dem gleichen Speicherort entsprechen. Das ist eigentlich eine gute Sache, da es der Sicherheit beiträgt und gut zur Natur von JavaScript passt. Es gibt aber Fälle, bei denen man beabsichtigt Anfragen an andere Server stellen will. Als offensichtliches Beispiel wäre hier die Datenabfrage bei Diensten wie Twitter oder ähnlichen. Hierfür gibt es zum Beispiel JSONP, JSON with Padding.

Was steckt hinter JSONP

JSONP nutzt eine “Lücke” um eine HTTP-Anfrage an einen Server zu senden, der nicht der gleichen Herkunft (Origin) wie der des JavaScripts entspricht. Die SRC-Attribute im Script-Tag können GET-Anfragen an Server beliebiger Herkunft senden. GET eigentlich im Sinne von: Schick mir mal das JavaScript (meist in Form einer .js-Datei) und nicht im Sinne von; Schick mir mal die JSON Daten.

Was aber beim Script-Tag eigentlich passiert ist, dass der Browser die JavaScript-Datei lädt und ausführt. Aus

<script type="text/javascript" src="http://meinserver.de/meinScript.js"></script>
view raw gistfile1.html hosted with ❤ by GitHub

wird also quasi ein:

<script type="text/javascript">
;(function() {
console.log("Hello World")
})();
</script>
view raw gistfile1.html hosted with ❤ by GitHub

Wie funktioniert nun JSONP?

JSONP nutzt eben beschriebenes Prinzip, indem der Server auf diese GET-Anfrage nicht mit normalen JSON-Daten antwortet, sondern noch ein Extra hinzufügt. Die JSON-Daten werden in einem Funktionsaufruf gehüllt, dieser Funktionsaufruf ist das P für Padding in JSONP. Das ist nicht unbedingt die beste Namenswahl gewesen, da Padding bei Webentwicklern durch CSS mental schon vorbelegt ist. Hier heisst es aber einfach nur, wie gesagt, dass die JSON-Daten in einem Funktionsaufruf gehüllt werden.

JSON: {"Name": "Benny Bennet", "Website": "http://ben.nyben.net"}
JSONP: verarbeiteDaten({"Name": "Benny Bennet", "Website": "http://ben.nyben.net"})
view raw gistfile1.js hosted with ❤ by GitHub

In der Regel teilt man dem Server per Parameter mit, in welchen Funktionsaufruf er die Daten hüllen soll.

<script type="text/javascript" src="http://some.tld/web/service?callback=verarbeiteDaten"></script>
... wird zu
<script type="text/javascript">
verarbeiteDaten({"Name": "Benny Bennet", "Website": "http://ben.nyben.net"})
</script>
view raw gistfile1.html hosted with ❤ by GitHub

Der geneigte JavaScripter müsste jetzt also nur noch irgendwo die Funktion “verarbeiteDaten” implementieren…

function verarbeiteDaten( data ) {
console.log(data["Name"]);
console.log(data["Website"]);
}
view raw gistfile1.js hosted with ❤ by GitHub

…und würde in seiner Console in diesem Beispiel die Ausgaben “Benny Bennet” und “http://ben.nyben.net” erhalten. Als Nachteil ist hier natürlich zu erwähnen, dass man dem Service 100% vertrauen können muss.

JavaScript Class à la bennybennet

Eines der schwierigsten Dinge, zumindest für mich, beim lernen von JavaScript, ist die Gewöhnung an funktionale Programmierung und die Implementierung von OO. Letzteres, weil JavaScript nicht die gängige Syntax aus andere C-Like-Block-Syntax-Sprachen benutzt, um “Objektbaupläne” aka Klassen zu beschreiben. In JavaScript gibt es keine Klassen. Um Objekte in JavaScript zu definieren, müssen wir also auf ein anderes Mittel zurückgreifen.

Eine Beispiel-Klasse in Java:

package de.bennybennet.examples;
public class Example extends Parent {
String exampleVarPP = "I'm only visible for every class in this package.";
private String exampleVarPriv = "I'm only visible for this class";
public Example() {
System.out.println("...entered the constructor");
}
public String getExampleVarPriv() {
System.out.println("...entered method of Example: Getter exampleVarPriv.");
return this.exampleVarPriv;
}
}
view raw Example.java hosted with ❤ by GitHub

JavaScript bietet für die Definition von Objekten sogenannte Prototypen. Ist man es gewohnt mit Klassen zu programmieren, dauert es häufig eine Weile, bis man prototypenbasierte Programmierung versteht. Der Sinn hinter Objekten und deren Vererbbarkeit ist die Wiederverwendung von Code. In Klassenbasierten sprachen geschieht dies, logisch, durch Klassen. Klassen können von anderen Klassen erben. Objekte entstehen durch Instanzierung von Klassen. In prototypbasierten Sprachen, werden Objekte durch das Klonen bereits bestehender Objekte erzeugt. Hierdurch kann auch eine Vererbung realisiert werden. Das Objekt “Child” wird aus einem Klon vom Objekt “Parent” erstellt und kann anschließend um Attribute und Methoden erweitert werden, die dann nur dem Objekt “Child” und Klons vom Objekt “Child” zur Verfügung stehen, nicht aber Objekt Parent oder weiteren Klons von diesem. Das Objekt Parent war der Prototyp für den Klon “Child”. Es werden keine Instanzen im Java-Sinne von Objektbauplänen (Klassen, Prototypen) in JavaScript erzeugt, weshalb das “new” in JavaScript sehr irreführend ist. Weiteres und näheres möchte ich gerne in einem anderen Post beschreiben.

Die folgende Notation, um klassenähnliche Definition von Objekten in JavaScript zu haben, ist hauptsächlich als akademisch anzusehen. Ich habe sie in meinen ersten Begegnungen mit JavaScript abseits von jQuery erstellt, hauptsächlich um JavaScript besser zu verstehen. Ist JS dein täglich Brot (oder besser: soll es das werden), empfehle ich stark, keine klassenähnlichen Konstrukte in JavaScript zu verwenden. Setzte dich intensiv mit prototypenbasierter Programmierung auseinander und verstehe, wie diese in JavaScript umgesetzt ist / funktioniert.

/* Simple JavaScript Inheritance
* First draft!
* @author Benny Bennet Jürgens (http://ben.nyben.net)
* CC-by-sa 3.0 - please provide my name and url
*/
;(function() {
"use strict";
this.BBClass = function(ctor, proto) {
ctor.prototype = proto || {};
ctor.prototype.constructor = ctor;
ctor.extends = function(parent) {
function ChildBB() {
parent.prototype.constructor.apply(this, arguments);
ctor.apply(this, arguments);
};
ChildBB.prototype = ( typeof Object.create !== 'function') ?
(function(parent) {
function F() {};
F.prototype = parent.prototype;
var prototype = new F();
prototype.constructor = ChildBB;
return prototype;
})(parent)
: Object.create(parent.prototype, { constructor: { value: ChildBB, enumerable: false }});
return ChildBB;
}
return ctor;
}
}).call(this);
var Person = BBClass(function(isDancing) {
console.log("person");
this.dancing = isDancing;
});
Person.prototype.dance = function() {
return this.dancing;
};
var Ninja = BBClass(function(isDancing) {
console.log("ninja");
}).extends(Person);
Ninja.prototype.swingSword = function() {
return true;
};
Ninja.prototype.arraytest = [1,2,3,4];
var p = new Person(true);
var n = new Ninja(false);
Person.prototype.test2 = function() { console.log("test2 bestanden"); };
console.log(n.arraytest);
console.log(p.dance());
console.log(n.dance());
console.log(n.swingSword())
p.test2();
n.test2();
console.log("inherit ok?")
console.log( p instanceof Object);
console.log( p instanceof Person);
console.log( p instanceof Person && p instanceof Object && n instanceof Ninja && n instanceof Person && n instanceof Object);
=> person
=> person
=> ninja
=> [1,2,3,4]
=> true
=> false
=> true
=> test2 bestanden
=> test2 bestanden
=> inherit ok?
=> true
=> true
=> true
view raw class.js hosted with ❤ by GitHub

Ich empfehle auch die Kommentare im Gist einmal durchzulesen. Dort habe ich meine Gedanken während der Entwicklung runtergeschrieben.

Quik-Hints #2

Ein paar kurze Anmerkungen und Hinweise zu verschiedenen Themen, die nicht unbedingt einen ganzen eigenen Post benötigen aber trotzdem erwähnenswert sind:

Custom styling für die Select-Box (auch im IE)

Custom Select-Box

Custom Select-Box

Ab und an kommen Designer auf die Idee, den Style der Select-Box so stark anzupassen, dass ein setzen des Backgrounds und vielleicht noch die Anpassung der Schriftart nicht reicht. Mit CSS3 ist jetzt auch sehr leicht viel mehr möglich. Wer aber noch den IE8 oder IE9 unterstützen muss, guckt in die Röhre. Ich weiß gar nicht, ob der IE10 dieses Feature schon unterstützt…?

Für die im folgenden beschriebene Möglichkeit ist JavaScript von nöten. Über die SelectBox für ein Span gelegt, welches das entsprechende Styling durch Background-Images oder sonstige CSS-Angaben bekommt. Die Ursprüngliche Select-Box liegt dank “z-index” aber über dem Span und wird per “opacity” durchsichtig gemacht. Der Inhalt des Spans wird per JavaScript immer auf die aktuelle Auswahl der Select-Box gesetzt.

Im Sinne von Progressive Enhancement, also der schrittweisen Anreicherung / Verbesserung, je nach Möglichkeiten, wird im Markup (HTML) zunächst nur eine normale Select-Box angegeben.

<select name="topics-select" id="topics-select" class="bb-styled">
<option selected>Themen</option>
<option>Thema 1</option>
<option>Thema 2</option>
</select>
view raw selectbox-style.html hosted with ❤ by GitHub

Das nötige Span-Element und der DIV-Container (Wrapper) wird, sofern JavaScript aktiviert ist, später hinzugefügt. Würden wir den Span und DIV-Container, inklusive Stylesheet-Angaben, direkt im Markup haben, könnte die Select-Box von einem User ohne JavaScript nicht mehr benutzt werden.

$('select.bb-styled').each(function(){
var title = $(this).attr('title');
if( $('option:selected', this).val() != '' ) title = $('option:selected',this).text();
var idName = $(this).attr('id') + '_container';
$(this).before('<div class="bb-styled-container" id="' + idName + '"></div>')
$('#' + idName).append(this);
$(this)
.css({'opacity':0})
.after('<span class="bb-styled">' + title + '</span>')
.change(function(){
val = $('option:selected',this).text();
$(this).parent().find('span').text(val);
})
});
view raw selectbox-style.js hosted with ❤ by GitHub

Hier noch das benötigte Stylesheet:

div.bb-styled-container { position:relative; margin: 50px; }
select.bb-styled {
position: relative;
z-index:10;
display: block;
-webkit-appearance:none;
-moz-appearance:none;
appearance:none;
cursor:pointer;
}
span.bb-styled {
position: absolute;
bottom: 0;
left: 0;
cursor: default;
z-index: 1;
}
span.bb-styled:after {
content: '<>';
display: inline-block;
transform: rotate(90deg);
-ms-transform: rotate(90deg);
-webkit-transform:rotate(90deg);
-ms-transform:rotate(90deg);
font-size: 10px;
height: 10px;
width: 10px;
float: right;
margin-top: -7px;
}
.bb-styled {
background-color: #ccc;
color: #000;
text-indent: 10px;
width: 200px;
border: 1px solid white;
border-radius: 4px;
font-size: 13px;
font-weight: normal;
font-family: Arial;
line-height: 18px;
}
view raw selectbox-style.css hosted with ❤ by GitHub

Demo-Code

Zum Abschluss das ganze noch in einem jsFiddle: http://jsfiddle.net/2zr78/2/

Bitte gerne Verbesserungsvorschläge in die Kommentare posten. Ich sehe es derzeit als ersten Entwurf. Vor allem mit der Struktur des CSS bin ich noch nicht richtig zufrieden, das Outcome (grauer Kasten ohne alles) ist hier nur zu Demozwecken, bei Zeiten lass ich mir aber mal etwas hübscheres einfallen. ;-p Der Code kann definitiv noch optimiert werden, zum Beispiel kann das JavaScript getrickse für die neusten WebKit-Versionen unterlassen werden.

BlackBerry Returns

BlackBerry Dev

© 2013 BlackBerry

Ich war die letzten Tage auf der MobileTechCon, welche mich bis auf eine Ausnahme nur mäßig überzeugen konnte: BlackBerry. Ich hatte vorher schon ein paar Videos vom neuen BlackBerry10 gesehen und besuchte auf der Konferenz eine Session von Luca Sale. Luca stellte die Entwicklung nativer Apps mit dem WebWorks SDK für BlackBerry10 vor. Ich war sofort begeistert! Native Apps mit HTML, CSS und JavaScript – performant, gut und ohne irgendwelches rumgewerkel mit Tools. Von der Entwicklung von iPhone Apps hält mich größtenteils die grausame Sprache ab, Objective-C bringt mir einfach keinen Spass. In JavaScript hingegen, hab ich mich in letzter Zeit ein wenig reinverguckt.

Gifts vom BlackBerry Booth auf der MobileTechCon13

Gifts vom BB-Booth

Nach der überzeugenden ersten Session besuchte ich weitere BlackBerry Sessions (Apps mit C, Apps mit Android, eine Keynote über das BlackBerry10-System ansich) und schaute natürlich auch am BlackBerry-Booth (Stand) vorbei. Als erstes sei hier noch erwähnt, dass alle dort anwesenden Mitarbeiter super freundlich und hilfsbereit waren und ich hatte nicht das Gefühl, dass sie das nur waren, weil sie für BlackBerry arbeiten, sondern weil sie das System wirklich mögen und es einem näher bringen wollen. BlackBerry gibt sich allgemein viel Mühe, es allen Entwicklern möglichst leicht zu machen, für das neue OS, basierend auf QNX, zu entwickeln. Die native Sprache von QNX ist C / C++, es soll wohl aber keine allzugroßen performance Unterschiede zu Apps mit dem WebWorks, Android oder Adobe AIR geben. Die hauptsächliche Strategie liegt wohl aber auf dem C und WebWorks SDK.

Was ist passiert?

BlackBerry (aka. RIM) hat in den letzten Jahren ein wenig eingekauft und dafür die Basis für ein wirklich gutes mobiles Betriebssystem gelegt. Alles fing wohl damit an, das Thorsten Heins erkannt hat, dass sie sich neu aufstellen müssen. 2010 wurde hierfür QNX aufgekauft. Viele weitere Käufe folgten, zum Beispiel Scoreloop um das Social-Gaming bestmöglich zu unterstützen. Ich weiß gar nicht mehr, was alles auf dem Einkaufszettel von RIM stand, aber es war eine Menge. In der Präsentation über die App-Entwicklung mit dem C-SDK (NDK) von Kamel Lajili auf der MobileTechCon13 wurde einige aufgezeigt, vielleicht komm ich noch an die Slides. Kamel ist übrigens für das deutsche BlackBerry Team tätig. Ich war verwundert, dass BlackBerry in Deutschland ansässig ist und dort sogar mit rund 300 Mitarbeitern recht stark vertreten ist.

 Ein paar Highlights

Das grundlegende Highlight ist sicher das QNX Betriebssystem, von dem ich mir hohe Sicherheit und Stabilität verspreche. Durch den Sandbox-Aufbau / modularen Aufbau können andere Apps das OS eigentlich nicht zum absturz bringen, bzw. andere Apps beeinflussen. Die Gestures (die Bedienung) des BlackBerrys fühlte sich sehr gut an und die Peek Funktionalität finde ich klasse. So ist es möglich mit einem kleinen wisch von linken Rand nur kurz zu “peeken” ob die Nachricht interessant ist (welche angekündigt wurde) ohne das laufende App zu unterbrechen. Wenn man die Wischgeste nicht zuende führt, sondern wieder zum rechten Rand zurück wischt, gelangt man wieder zurück zu der (jederzeit sichtbaren) zuletzt benutzten App.

Die Entwicklung für das BlackBerry10 System sollte für einen ganz großen Teil der Entwickler sehr einfach möglich sein, sodass ich mir eine große App-Anzahl erhoffe. Persönlich freue ich mich sehr über das WebWorks SDK und hoffe schnell an ein BlackBerry Z10 oder Q10 zu gelangen um die Apps nicht nur im sehr gelungen Simulator und / oder Emulator auszuprobieren. Der Emulator ist wirklich klasse, es ist ein Chrome-Plugin, in welchem man die mit dem WebWorks geschriebenen Apps testen kann. Dort gibt es nicht nur eine Emulation für die BlackBerry Geräte sondern auch für weitere Smatphones und Tablets anderer Herrsteller, wie zum Beispiel das Nexus 7 von Google.

 

Ein Nachteil von jQuery? Performance!

jQuery ist eine beliebte Library zur DOM-Manipulation (und mehr) in JavaScript. Diese Library hat wahrscheinlich mehr Anwender zu JavaScript gebracht als irgendetwas anderes. Sie beschleunigt den Entwicklungsprozess erheblich, vor allem für Anfänger und bei Cross-Browser-Problemen. Vor noch nicht allzu langer Zeit war Letzteres ein echtes Problem. Heute bietet JavaScript, abgesehen von der Implementierung des InternetExplorers, viele / ausreichend Funktionen zur DOM-Manipulation.

Beim Review eines JavaScript-Codes eines Kollegen, welcher jQuery nutzt, unterhielten wir uns zunächst nur über die performance Unterschiede zwischen Caching und nicht Caching von Elementen zur Manipulation der Width-Eigenschaft. Es wurde eine $(selector).each() verwendet und es ging darum, ob innerhalb der Each-Function das aktuelle DOM-Element gecached wird, oder nicht.

// !--- Caching
$(selector).each(function( index ) {
  var $el = $(this);
  // 2-3 DOM-Manipulationen an dem Element
  // mit Benutzung von $el, z.B. $el.width()
});

// !--- kein Caching
$(selector).each(function( index ) {
  // 2-3 DOM-Manipulationen an dem Element
  // mit Benutzung von $(this), z.B. $(this).width()
});

Da es wirklich nur zwei – drei Anweisungen waren, ging es zunächst nur darum, ob die extra Zeile mit der Anweisung des Cachings nötig ist oder ob es in diesem Fall wirklich Vorteile in der Performance bringt. Der Performance-Frage bin ich dann mit jsPerf hinterher gegangen. Dank einer kleinen Diskussion kamen zwei Dinge zum Vorschein:

  1. jQuery.width() ist extrem langsam und sollte durch jQuery.css() ersetzt werden.
  2. Plain JavaScript schlägt die jQuery Performance um viele 100 wenn nicht sogar 1000%.

Zum ersten Punkt:

“One thing that hasn’t changed is the return value of the .width() method. As it’s always been documented, it gets and/or sets the “content” width of an element, and that is regardless of the CSS box-sizing being used by the element. However, jQuery 1.8 now needs to check the box-sizing property whenever you use .width() so that it can decide whether it needs to subtract out the padding and border width. That can be expensive—up to 100 times more expensive on Chrome!”
http://blog.jquery.com/2012/08/16/jquery-1-8-box-sizing-width-csswidth-and-outerwidth/

Auf obiges Zitat bin ich Dank eines Users in der Google+ JavaScript Community gekommen. Ich hatte dort meine jsPerf-Ergebnisse vorgestellt. Einige hatten meiner ursprünglichen Version auch noch einiges hinzugefügt, sodass wir mittlerweile bei der achten Revision sind. Die Revision 3 war die von mir vorgestellte Revision und hat die meisten Testergebnisse, weshalb sie auf jeden Fall auch beachtet werden sollte. Ansonsten empfehle ich Revision 8, weil dort alle Anmerkungen und Erweiterungen der Community enthalten sind*:

http://jsperf.com/jquery-cache-no-cache/8

Die Ergebnisse, die dort zu sehen sind, sind es, welche mich zu der Aussage des zweiten Punktes kommen lassen. Selbst wenn man jQuery.css() benutzt, hat man noch weit weniger Performance – verglichen mit vanilla JS. Vor allem für den mobilen Bereich ist das sicher sehr interessant, ist dort doch die Performance dringend benötigt und man muss sehr selten auf den IE Rücksicht nehmen.

*** Update am 12.07.2014
Habe nun noch eine Version erstellt, in der einige Fehler der Vorgänger behoben wurden und ein paar neue Vergleiche hinzugekommen sind. Außerdem habe ich auf die aktuelle jQuery Version (2.x) umgestellt. Trotz allem ist jQuery weiterhin in diesem Vergleich um ein vielfaches langsamer:

http://jsperf.com/jquery-cache-no-cache/13