Ich schreibe schon seit langer Zeit JavaScript-Code und kann mich nicht einmal daran erinnern, wann ich angefangen habe. Ich bin sehr begeistert von dem, was JavaScript in den letzten Jahren erreicht hat; ich hatte das Glück, von diesen Errungenschaften profitieren zu dürfen. Ich habe eine ganze Reihe von Artikeln, Kapiteln und ein Buch darüber geschrieben, und dennoch entdecke ich immer noch Neues über die Sprache. Was folgt, ist eine Beschreibung von Programmiertechniken, die mich in der Vergangenheit dazu gebracht haben, „Ah!“ zu sagen, Techniken, die Sie jetzt ausprobieren sollten, anstatt darauf zu warten, irgendwann in der Zukunft auf sie zu stoßen.
Prägnantes Schreiben
Eines meiner Lieblingsdinge in JavaScript ist die Kurzschriftmethode zum Generieren von Objekten und Arrays. Wenn Sie früher ein Objekt erstellen wollten, gingen Sie folgendermaßen vor:
1 var car = new Object(); 2 car.colour = 'red'; 3 car.wheels = 4; 4 car.hubcaps = 'spinning'; 5 car.age = 4;
Folgendes würde den gleichen Effekt erzielen:
1 var car = { 2 colour:'red', 3 wheels:4, 4 hubcaps:'spinning', 5 age:4 6 }
Viel einfacher, Sie tun es nicht Ich muss es immer wieder verwenden. Der Name dieses Objekts. Auf diese Weise wird car möglicherweise auf das Problem „invalidUserInSession“ stoßen. Denken Sie jedoch daran, dass Sie kein Komma vor die schließende Klammer schreiben.
Eine weitere sehr praktische Abkürzung ist für Arrays. Die traditionelle Art, ein Array zu definieren, ist wie folgt:
1 var moviesThatNeedBetterWriters = new Array( 2 'Transformers','Transformers2','Avatar','IndianaJones 4' 3 );
Die Kurzfassung lautet wie folgt:
1 var moviesThatNeedBetterWriters = [ 2 'Transformers','Transformers2','Avatar','IndianaJones 4' 3 ];
Bei Arrays gibt es tatsächlich kein Problem Diagrammgruppenfunktion. Aber Sie werden oft Leute finden, die das Auto oben so definieren
1 var car = new Array(); 2 car['colour'] = 'red'; 3 car['wheels'] = 4; 4 car['hubcaps'] = 'spinning'; 5 car['age'] = 4;
Arrays sind nicht allmächtig; wenn dies nicht richtig geschrieben ist, wird es die Leute verwirren. Graphgruppen sind eigentlich Funktionen von Objekten, und die beiden Konzepte werden häufig verwechselt.
Eine weitere sehr coole Kurzschriftmethode ist die Verwendung der ternären bedingten Notation. Sie müssen es nicht so schreiben...
var direction; if(x < 200){ direction = 1; } else { direction = -1; }
Sie können es mit der ternären bedingten Notation vereinfachen:
var direction = x < 200 ? 1 : -1;
Wenn die Bedingung wahr ist, nehmen Sie den Wert nach dem Fragezeichen, andernfalls nehmen Sie den Wert nach dem Doppelpunkt.
Speichern von Daten im JSON-Format
Bevor ich JSON entdeckte, habe ich alle möglichen verrückten Methoden verwendet, um Daten in den in JavaScript inhärenten Datentypen zu speichern, wie zum Beispiel: Arrays, Strings, Zwischenstufen, gemischt mit einfachen um Glyphen und andere unangenehme Dinge zu teilen. Alles änderte sich, als Douglas Crockford JSON erfand. Mithilfe von JSON können Sie JavaScript-eigene Funktionen verwenden, um Daten in komplexen Formaten zu speichern, und sie können ohne zusätzliche Konvertierung direkt abgerufen und verwendet werden. JSON ist die Abkürzung für „JavaScript Object Notation“, die die beiden oben genannten Abkürzungen verwendet. Wenn Sie also ein Band beschreiben möchten, könnten Sie es so schreiben:
01 var band = { 02 "name":"The Red Hot Chili Peppers", 03 "members":[ 04 { 05 "name":"Anthony Kiedis", 06 "role":"lead vocals" 07 }, 08 { 09 "name":"Michael 'Flea' Balzary", 10 "role":"bass guitar, trumpet, backing vocals" 11 }, 12 { 13 "name":"Chad Smith", 14 "role":"drums,percussion" 15 }, 16 { 17 "name":"John Frusciante", 18 "role":"Lead Guitar" 19 } 20 ], 21 "year":"2009" 22 }
Sie können JSON direkt in JavaScript verwenden, es in einer Funktion kapseln oder es sogar als Rückgabewert einer verwenden API. Wir nennen dies JSON-P und viele APIs verwenden dieses Format.
Sie können einen Datenanbieter aufrufen und JSON-P-Daten direkt im Skriptcode zurückgeben:
01 <div id="delicious"></div><script> 02 function delicious(o){ 03 var out = '<ul>'; 04 for(var i=0;i<o.length;i++){ 05 out += '<li><a href="' + o[i].u + '">' + 06 o[i].d + '</a></li>'; 07 } 08 out += '</ul>'; 09 document.getElementById('delicious').innerHTML = out; 10 } 11 </script> 12 <script src="http://feeds.delicious.com/v2/json/codepo8/javascript?count=15&callback=delicious"></script>
Hiermit wird die von der Delicious-Website bereitgestellte Webdienstfunktion aufgerufen, um die neuesten Informationen zu erhalten Daten im JSON-Format Eine ungeordnete Liste von Lesezeichen.
Grundsätzlich ist JSON die portabelste Methode zur Beschreibung komplexer Datenstrukturen und kann im Browser ausgeführt werden. Sie können es sogar in PHP mit der Funktion json_decode() ausführen. Eine Sache, die mich an den integrierten Funktionen von JavaScript (Math, Array und String) überrascht hat, ist, dass ich nach dem Studium der Mathematik- und String-Funktionen in JavaScript festgestellt habe, dass sie meine Programmierarbeit erheblich vereinfachen können. Mit ihnen können Sie komplexe Schleifenverarbeitung und bedingte Beurteilungen einsparen. Wenn ich zum Beispiel eine Funktion implementieren muss, um die größte Zahl in einem Zahlenarray zu finden, habe ich die Schleife so geschrieben:
1 var numbers = [3,342,23,22,124]; 2 var max = 0; 3 for(var i=0;i<numbers.length;i++){ 4 if(numbers[i] > max){ 5 max = numbers[i]; 6 } 7 } 8 alert(max);
Wir können es ohne Schleifen machen:
1 var numbers = [3,342,23,22,124]; 2 numbers.sort(function(a,b){return b - a}); 3 alert(numbers[0]);
Es ist zu beachten, dass Sie ein Array mit numerischen Zeichen nicht sort() verwenden können, da es in diesem Fall nur in alphabetischer Reihenfolge sortiert wird. Wenn Sie mehr über die Verwendung erfahren möchten, können Sie diesen guten Artikel über sort() lesen.
Eine weitere interessante Funktion ist Math.max(). Diese Funktion gibt die größte Zahl unter den Zahlen im Parameter zurück:
Math.max(12,123,3,2,433,4); // returns 433
Da diese Funktion die Zahl überprüfen und die größte zurückgeben kann, können Sie damit die Unterstützung des Browsers für eine bestimmte Funktion testen Status:
1 var scrollTop=Math.max( 2 doc.documentElement.scrollTop, 3 doc.body.scrollTop 4 );
Dies wird zur Lösung von IE-Problemen verwendet. Sie können den scrollTop-Wert der aktuellen Seite abrufen, aber je nach DOCTYPE auf der Seite speichert nur eine der beiden oben genannten Eigenschaften diesen Wert und die andere Eigenschaft ist undefiniert, sodass Sie dies mithilfe von Math.max erhalten können () Nummer. Lesen Sie diesen Artikel, um mehr über die Verwendung mathematischer Funktionen zur Vereinfachung von JavaScript zu erfahren.
Ein weiteres Paar sehr nützlicher Funktionen zum Bearbeiten von Zeichenfolgen sind split() und join(). Ich denke, das repräsentativste Beispiel ist das Schreiben einer Funktion zum Anhängen von CSS-Stilen an Seitenelemente.
是这样的,当你给页面元素附加一个CSS class时,要么它是这个元素的第一个CSS class,或者是它已经有了一些class, 需要在已有的class后加上一个空格,然后追加上这个class。而当你要去掉这个class时,你也需要去掉这个class前面的空格(这个在过去非常重要,因为有些老的浏览器不认识后面跟着空格的class)。
于是,原始的写法会是这样:
1 function addclass(elm,newclass){ 2 var c = elm.className; 3 elm.className = (c === '') ? newclass : c+' '+newclass; 4 }
你可以使用 split() 和 join() 函数自动完成这个任务:
1 function addclass(elm,newclass){ 2 var classes = elm.className.split(' '); 3 classes.push(newclass); 4 elm.className = classes.join(' '); 5 }
这会确保所有的class都被空格分隔,而且你要追加的class正好放在最后。
事件委派
Web应用都是由事件驱动运转的。我喜欢事件处理,尤其喜欢自己定义事件。它能使你的产品可扩展,而不用改动核心代码。有一个很大的问题(也可以说是功能强大的表现),是关于页面上事件的移除问题。你可以对某个元素安装一个事件监听器,事件监听器就开始运转工作。但页面上没有任何指示说明这有个监听器。因为这种不可表现的问题 (这尤其让一些新手头疼) ,以及像IE6这样的”浏览器“在太多的使用事件监听时会出现各种的内存问题,你不得不承认尽量少使用事件编程是个明智的做法。
于是 事件委托 就出现了。
当页面上某个元素上的事件触发时,而在 DOM 继承关系上,这个元素的所有子元素也能接收到这个事件,这时你可以使用一个在父元素上的事件处理器来处理,而不是使用一堆的各个子元素上的事件监听器来处理。究竟是什么意思?这样说吧,页面上有很多超链接,你不想直接使用这些链接,想通过一个函数来调用这个链接,HTML代码是这样的:
1 <h2>Great Web resources</h2> 2 <ul id="resources"> 3 <li><a href="http://opera.com/wsc">Opera Web Standards Curriculum</a></li> 4 <li><a href="http://sitepoint.com">Sitepoint</a></li> 5 <li><a href="http://alistapart.com">A List Apart</a></li> 6 <li><a href="http://yuiblog.com">YUI Blog</a></li> 7 <li><a href="http://blameitonthevoices.com">Blame it on the voices</a></li> 8 <li><a href="http://oddlyspecific.com">Oddly specific</a></li> 9 </ul>
常见的做法是通过循环这些链接,将每个链接上附加一个事件处理器:
01 // 典型的事件处理例子 02 (function(){ 03 var resources = document.getElementById('resources'); 04 var links = resources.getElementsByTagName('a'); 05 var all = links.length; 06 for(var i=0;i<all;i++){ 07 // Attach a listener to each link 08 links[i].addEventListener('click',handler,false); 09 }; 10 function handler(e){ 11 var x = e.target; // Get the link that was clicked 12 alert(x); 13 e.preventDefault(); 14 }; 15 })();
我们用一个事件处理器也能完成这项任务:
01 (function(){ 02 var resources = document.getElementById('resources'); 03 resources.addEventListener('click',handler,false); 04 function handler(e){ 05 var x = e.target; // get the link tha 06 if(x.nodeName.toLowerCase() === 'a'){ 07 alert('Event delegation:' + x); 08 e.preventDefault(); 09 } 10 }; 11 })();
因为点击事件就发生在这些页面元素里,你要做的就是比较它们的 nodeName,找出应该回应这个事件的那个元素。
免责声明:上面说的这两个关于事件的例子,在所有浏览器里都能运行,除了IE6,在IE6上你需要使用一个事件模型,而不是简单的W3C的标准实现。这也就是我们推荐使用一些工具包的原因。
这种方法的好处并不是仅限于把多个事件处理器缩减为一个。你想想,举个例子,你需要动态的往这个链接表里追加更多的链接。使用事件委托后,你就不需要做其它修改了;否则的话,你需要重新循环这个链接表,重新给每个链接安装事件处理器。
匿名函数和模块化
在JavaScript里最令人懊恼的事情是变量没有使用范围。任何变量,函数,数组,对象,只要不在函数内部,都被认为是全局的,这就是说,这个页面上的其它脚本也可以访问它,而且可以覆盖重写它。
解决办法是,把你的变量放在一个匿名函数内部,定义完之后立即调用它。例如,下面的写法将会产生三个全局变量和两个全局函数:
1 var name = 'Chris'; 2 var age = '34'; 3 var status = 'single'; 4 function createMember(){ 5 // [...] 6 } 7 function getMemberDetails(){ 8 // [...] 9 }
如果这个页面上的其它脚本里也存在一个叫 status 的变量,麻烦就会出现。如果我们把它们封装在一个 myApplication 里,这个问题就迎刃而解了:
01 var myApplication = function(){ 02 var name = 'Chris'; 03 var age = '34'; 04 var status = 'single'; 05 function createMember(){ 06 // [...] 07 } 08 function getMemberDetails(){ 09 // [...] 10 } 11 }();
但是,这样一来,在函数外面就没有什么功能了。如果这是你需要的,那就可以了。你还可以省去函数的名称:
01 (function(){ 02 var name = 'Chris'; 03 var age = '34'; 04 var status = 'single'; 05 function createMember(){ 06 // [...] 07 } 08 function getMemberDetails(){ 09 // [...] 10 } 11 })();
如果你想在函数外面也能使用里面的东西,那就要做些修改。为了能访问 createMember() 或 getMemberDetails(),你需要把它们变成 myApplication的属性,从而把它们暴露于外部的世界:
01 var myApplication = function(){ 02 var name = 'Chris'; 03 var age = '34'; 04 var status = 'single'; 05 return{ 06 createMember:function(){ 07 // [...] 08 }, 09 getMemberDetails:function(){ 10 // [...] 11 } 12 } 13 }(); 14 //myApplication.createMember() 和 15 //myApplication.getMemberDetails() 就可以使用了。
这被称作 module 模式或 singleton。Douglas Crockford 多次谈到过这些,Yahoo User Interface Library YUI 里对此有大量的使用。但这样一来让我感到不便的是,我需要改变句式来使函数和变量能被外界访问。更甚者,调用时我还需要加上myApplication 这个前缀。所以,我不喜欢这样做,我更愿意简单的把需要能被外界访问的元素的指针导出来。这样做后,反倒简化了外界调用的写法:
01 var myApplication = function(){ 02 var name = 'Chris'; 03 var age = '34'; 04 var status = 'single'; 05 function createMember(){ 06 // [...] 07 } 08 function getMemberDetails(){ 09 // [...] 10 } 11 return{ 12 create:createMember, 13 get:getMemberDetails 14 } 15 }(); 16 //现在写成 myApplication.get()和 myApplication.create() 就行了。
我把这个称作 “revealing module pattern.”
可配置化
一旦我把所写的JavaScript代码发布到这个世界上,就有人想改动它,通常是人们想让它完成一些它本身完成不了的任务—但通常也是我写的程序不够灵活,没有提供用户可自定义的功能。解决办法是给你的脚本增加一个配置项对象。我曾经写过一篇深入介绍JavaScript配置项对象的文章,下面是其中的要点:
Fügen Sie Ihrem Skript ein Objekt namens „Konfiguration“ hinzu.
In diesem Objekt werden alle Dinge gespeichert, die bei der Verwendung dieses Skripts häufig geändert werden:
CSS-ID und Klassenname
Schaltflächenname, Beschriftungswort usw. ;
Werte wie „Anzahl der Bilder pro Seite“, „Anzeigegröße der Bilder“;
Veranstaltungsort, Ort und Spracheinstellungen.
Geben Sie dieses Objekt als öffentliche Eigenschaft an den Benutzer zurück, damit der Benutzer es ändern und überschreiben kann.
Normalerweise ist dies der letzte Schritt in Ihrem Programmierprozess. Ich habe diese in einem Beispiel zusammengefasst: „Fünf Dinge, die Sie an einem Skript tun müssen, bevor Sie es an den nächsten Entwickler übergeben.“ Tatsächlich möchten Sie, dass Ihr Code mit einigen Änderungen auch für die Benutzer nützlich ist an ihre jeweiligen Bedürfnisse anzupassen. Wenn Sie diese Funktion implementieren, erhalten Sie weniger verwirrende E-Mails von Leuten, die sich über Ihr Skript beschweren und Ihnen mitteilen, dass jemand Ihr Skript geändert hat und es hervorragend funktioniert.
Interaktion mit dem Hintergrund
In so vielen Jahren Programmiererfahrung habe ich eine wichtige Sache gelernt: JavaScript ist eine hervorragende Sprache für die Entwicklung von Schnittstelleninteraktionen, aber wenn es verwendet wird, um Zahlen zu knacken oder Der Zugriff auf Datenquellen ist etwas mühsam.
Anfangs habe ich JavaScript als Ersatz für Perl gelernt, weil ich es hasste, den Code in den cgi-bin-Ordner kopieren zu müssen, um Perl zum Laufen zu bringen. Später wurde mir klar, dass ich eine Hintergrundarbeitssprache verwenden sollte, um die Hauptdaten zu verarbeiten, anstatt JavaScript alles erledigen zu lassen. Wichtiger ist, dass wir Sicherheits- und Sprachfunktionen berücksichtigen müssen.
Wenn ich auf einen Webdienst zugreife, kann ich Daten im JSON-P-Format abrufen und im Client-Browser verschiedene Datenkonvertierungen durchführen. Wenn ich jedoch einen Server habe, stehen mir mehr Möglichkeiten zur Konvertierung zur Verfügung Daten kann ich serverseitig im JSON- oder HTML-Format generieren und an den Client zurückgeben sowie Daten und andere Vorgänge zwischenspeichern. Wenn Sie diese im Voraus verstehen und vorbereiten, werden Sie auf lange Sicht davon profitieren und sich viel Kopfzerbrechen ersparen. Das Schreiben von Programmen, die in allen Browsern funktionieren, ist Zeitverschwendung. Verwenden Sie ein Toolkit!
Als ich anfing, mich mit der Webentwicklung zu beschäftigen, kämpfte ich lange mit der Frage, ob ich beim Zugriff auf eine Seite document.all oder document.layers verwenden sollte. Ich habe mich für document.layers entschieden, weil mir die Idee gefällt, dass jede Ebene ein eigenes Dokument ist (und ich zu viele document.writes schreibe, um Elemente zu generieren). Das Ebenenmuster schlug schließlich fehl, also begann ich, document.all zu verwenden. Ich war froh, als Netscape 6 nur die Unterstützung des W3C-DOM-Modells ankündigte, aber den Benutzern war das eigentlich egal. Der Benutzer sieht lediglich, dass dieser Browser etwas nicht anzeigen kann, was die meisten Browser ordnungsgemäß anzeigen können – es liegt ein Problem mit unserer Codierung vor. Wir schreiben kurzsichtigen Code, der nur in der aktuellen Umgebung ausgeführt werden kann, und leider ändert sich unsere Betriebsumgebung ständig.
Ich habe zu viel Zeit damit verschwendet, mich mit Kompatibilitätsproblemen mit verschiedenen Browsern und Versionen zu befassen. Wenn ich diese Art von Problemen gut bewältigen kann, habe ich gute Jobchancen. Aber jetzt müssen wir diesen Schmerz nicht mehr ertragen.
Einige Toolkits wie YUI, jQuery und Dojo können uns bei der Bewältigung dieser Art von Problemen helfen. Sie lösen verschiedene Browserprobleme, indem sie verschiedene Schnittstellenimplementierungen abstrahieren, z. B. Versionsinkompatibilität, Designfehler usw., und ersparen uns so den Schmerz. Sofern Sie keine Betaversion des Browsers testen möchten, fügen Sie niemals Code hinzu, um die Fehler des Browsers in Ihrem Programm zu beheben, da Sie wahrscheinlich vergessen, den Code zu löschen, wenn der Browser das Problem behoben hat.
Andererseits ist es auch kurzsichtig, sich ausschließlich auf Toolkits zu verlassen. Toolkits können Ihnen bei der schnellen Entwicklung helfen, aber wenn Sie JavaScript nicht tiefgreifend verstehen, können Sie auch etwas falsch machen.