服务器君一共花费了1201.828 ms进行了4次数据库查询,努力地为您提供了这个页面。

I’ve been writing JavaScript code for much longer than I care to remember. I am very excited about the language’s recent success; it’s good to be a part of that success story. I’ve written dozens of articles, book chapters and one full book on the matter, and yet I keep finding new things. Here are some of the “aha!” moments I’ve had in the past, which you can try out rather than waiting for them to come to you by chance.

Shortcut Notations 简洁写法

One of the things I love most about JavaScript now is shortcut notations to generate objects and arrays. So, in the past when we wanted to create an object, we wrote:


var car = new Object();
car.colour = 'red';
car.wheels = 4;
car.hubcaps = 'spinning';
car.age = 4;

The same can be achieved with:


var car = {

Much shorter, and you don’t need to repeat the name of the object. Right now, car is fine, but what happens when you use invalidUserInSession? The main gotcha in this notation is IE. Never ever leave a trailing comma before the closing curly brace or you’ll be in trouble.

这样就简单多了,你不需要反复使用这个对象的名称。这样 car 就定义好了,也许你会遇到 invalidUserInSession 的问题,这只有你在使用IE时会碰到,只要记住一点,不要右大括号前面写分号,你就不会有麻烦。

The other handy shortcut notation is for arrays. The old school way of defining arrays was this:


var moviesThatNeedBetterWriters = new Array(
  'Transformers','Transformers2','Avatar','Indiana Jones 4'

The shorter version of this is:


var moviesThatNeedBetterWriters = [
  'Transformers','Transformers2','Avatar','Indiana Jones 4'

The other thing about arrays is that there is no such thing as an associative array. You will find a lot of code examples that define the above car example like so:

对于数组,这里有个问题,其实没有什么图组功能。但你会经常发现有人这样定义上面的 car ,就像这样:

var car = new Array();
car['colour'] = 'red';
car['wheels'] = 4;
car['hubcaps'] = 'spinning';
car['age'] = 4;

This is not Sparta; this is madness—don’t bother with this. “Associative arrays” is a confusing name for objects.


Another very cool shortcut notation is the ternary notation for conditions. So, instead of the following…


var direction;
if(x < 200){
  direction = 1;
} else {
  direction = -1;

… You could write a shorter version using the ternary notation:


var direction = x < 200 ? 1 : -1;

The true case of the condition is after the question mark, and the other case follows the colon.

当条件为true 时取问号后面的值,否则取冒号后面的值。

JSON As A Data Format 用 JSON 形式存储数据

Before I discovered JSON to store data, I did all kinds of crazy things to put content in a JavaScript-ready format: arrays, strings with control characters to split, and other abominations. The creation of JSON by Douglas Crockford changed all that. Using JSON, you can store complex data in a format that is native to JavaScript and doesn't need any extra conversion to be used immediately.

Douglas Crockford 发明了JSON 之后,一切全变了。使用JSON,你可以使用JavaScript自有功能把数据存贮成复杂的格式,而且不需要再做其它的额外转换,直接可以访问使用。

JSON is short for "JavaScript Object Notation" and uses both of the shortcuts we covered earlier.

JSON 是 “JavaScript Object Notation” 的缩写,它用到了上面提到的两种简写方法。

So, if I wanted to describe a band, for example, I could do the following:


var band = {
  "name":"The Red Hot Chili Peppers",
      "name":"Anthony Kiedis",
      "role":"lead vocals"
      "name":"Michael 'Flea' Balzary",
      "role":"bass guitar, trumpet, backing vocals"
      "name":"Chad Smith",
      "name":"John Frusciante",
      "role":"Lead Guitar"

You can use JSON directly in JavaScript and, when wrapped in a function call, even as a return format of APIs. This is called JSON-P and is supported by a lot of APIs out there. You can use a data endpoint, returning JSON-P directly in a script node:

你可以在JavaScript里直接使用JSON,可以把它封装在函数里,甚至作为一个API的返回值形式。我们把这称作 JSON-P ,很多的API都使用这种形式。你可以调用一个数据提供源,在script代码里直接返回 JSON-P 数据:

<div id="delicious"></div><script>
function delicious(o){
  var out = '<ul>';
  for(var i=0;i<o.length;i++){
    out += '<li><a href="' + o[i].u + '">' +
           o[i].d + '</a></li>';
  out += '</ul>';
  document.getElementById('delicious').innerHTML = out;
<script src="http://feeds.nowamagic.net/v2/json/codepo8/javascript?count=15&callback=delicious"></script>

This calls the Delicious Web service to get my latest JavaScript bookmarks in JSON format and then displays them as an unordered list.

这是调用 Delicious 网站提供的 Web service 功能,获得JSON格式的最近的无序书签列表。

In essence, JSON is probably the most lightweight way of describing complex data—and it runs in a browser. You can even use it in PHP using the json_decode() function.

基本上,JSON是最轻便的描述复杂数据结构的方法,而且它能在浏览器里运行。你甚至可以在PHP里用 json_decode() 函数来运行它。

Native JavaScript Functions (Math, Array And String) JavaScript的自带函数(Math, Array 和 String)

One thing that amazed me is how much easier my life got once I read up thoroughly on the math and string functions of JavaScript. You can use these to avoid a lot of looping and conditions. For example, when I had the task of finding the largest number in an array of numbers, I used to write a loop, like so:


var numbers = [3,342,23,22,124];
var max = 0;
for(var i=0;i<numbers.length;i++){
  if(numbers[i] > max){
    max = numbers[i];

This can be achieved without a loop:


var numbers = [3,342,23,22,124];
numbers.sort(function(a,b){return b - a});

Notice that you cannot use sort() on a number array because it sorts lexically.

需要注意的是,你不能对一个数字字符数组进行 sort() ,因为这种情况下它只会按照字母顺序进行排序。

Another interesting method is Math.max(). This one returns the largest number from a list of parameters:

再有一个有意思的函数就是 Math.max()。这个函数返回参数里的数字里最大的一个数字:

Math.max(12,123,3,2,433,4); // returns 433

Because this tests for numbers and returns the largest one, you can use it to test for browser support of certain properties:


var scrollTop= Math.max(

This works around an Internet Explorer problem. You can read out the scrollTop of the current document, but depending on the DOCTYPE of the document, one or the other property is assigned the value. When you use Math.max() you get the right number because only one of the properties returns one; the other will be undefined. You can read more about shortening JavaScript with math functions here.

这个是用来解决IE问题的。你可以获得当前页面的 scrollTop 值,但是根据页面上 DOCTYPE 的不同,上面这两个属性中只有一个会存放这个值,而另外一个属性会是 undefined,所以你可以通过使用 Math.max() 得到这个数。 阅读这篇文章你会得到更多的关于使用数学函数来简化JavaScript的知识。

Other very powerful functions to manipulate strings are split() and join(). Probably the most powerful example of this is writing a function to attach CSS classes to elements.

另外有一对非常有用的操作字符串的函数是 split() 和 join()。我想最有代表性的例子应该是,写一个功能,用来给页面元素附加CSS样式。

The thing is, when you add a class to a DOM element, you want to add it either as the first class or to already existing classes with a space in front of it. When you remove classes, you also need to remove the spaces (which was much more important in the past when some browsers failed to apply classes with trailing spaces).

是这样的,当你给页面元素附加一个CSS class时,要么它是这个元素的第一个CSS class,或者是它已经有了一些class , 需要在已有的class后加上一个空格,然后追加上这个class。而当你要去掉这个class时,你也需要去掉这个class前面的空格(这个在过去非常重要,因为有些老的浏览器不认识后面跟着空格的class)。

So, the original function would be something like:


function addclass(elm,newclass){
  var c = elm.className;
  elm.className = (c === '') ? newclass : c+' '+newclass;

You can automate this using the split() and join() methods:

你可以使用 split() 和 join() 函数自动完成这个任务:

function addclass(elm,newclass){
  var classes = elm.className.split(' ');
  elm.className = classes.join(' ');

This automatically ensures that classes are space-separated and that yours gets tacked on at the end.


Event Delegation 事件委派

Events make Web apps work. I love events, especially custom events, which make your products extensible without your needing to touch the core code. The main problem (and actually one of its strengths) is that events are removed from the HTML—you apply an event listener to a certain element and then it becomes active. Nothing in the HTML indicates that this is the case though. Take this abstraction issue (which is hard for beginners to wrap their heads around) and the fact that "browsers" such as IE6 have all kind of memory problems and too many events applied to them, and you'll see that not using too many event handlers in a document is wise.

Web应用都是由事件驱动运转的。我喜欢事件处理,尤其喜欢自己定义事件。它能使你的产品可扩展,而不用改动核心代码。有一个很大的问题(也可以说是功能强大的表现),是关于页面上事件的移除问题。你可以对某个元素安装一个事件监听器,事件监听器就开始运转工作。但页面上没有任何指示说明这有个监听器。因为这种不可表现的问题 (这尤其让一些新手头疼) ,以及像IE6这样的”浏览器“在太多的使用事件监听时会出现各种的内存问题,你不得不承认尽量少使用事件编程是个明智的做法。

This is where event delegation comes in. When an event happens on a certain element and on all the elements above it in the DOM hierarchy, you can simplify your event handling by using a single handler on a parent element, rather than using a lot of handlers.

于是 事件委托 就出现了。当页面上某个元素上的事件触发时,而在 DOM 继承关系上,这个元素的所有子元素也能接收到这个事件,这时你可以使用一个在父元素上的事件处理器来处理,而不是使用一堆的各个子元素上的事件监听器来处理。

What do I mean by that? Say you want a list of links, and you want to call a function rather than load the links. The HTML would be:


<h2>Great Web resources</h2>
<ul id="resources">
  <li><a href="http://opera.com/wsc">Opera Web Standards Curriculum</a></li>
  <li><a href="http://sitepoint.com">Sitepoint</a></li>
  <li><a href="http://alistapart.com">A List Apart</a></li>
  <li><a href="http://yuiblog.com">YUI Blog</a></li>
  <li><a href="http://blameitonthevoices.com">Blame it on the voices</a></li>
  <li><a href="http://oddlyspecific.com">Oddly specific</a></li>

The normal way to apply event handlers here would be to loop through the links:


// Classic event handling example
  var resources = document.getElementById('resources');
  var links = resources.getElementsByTagName('a');
  var all = links.length;
  for(var i=0;i<all;i++){
    // Attach a listener to each link
  function handler(e){
    var x = e.target; // Get the link that was clicked

This could also be done with a single event handler:


  var resources = document.getElementById('resources');
  function handler(e){
    var x = e.target; // get the link tha
    if(x.nodeName.toLowerCase() === 'a'){
      alert('Event delegation:' + x);

Because the click happens on all the elements in the list, all you need to do is compare the nodeName to the right element that you want to react to the event.

因为点击事件就发生在这些页面元素里,你要做的就是比较它们的 nodeName,找出应该回应这个事件的那个元素。

Disclaimer: while both of the event examples above work in browsers, they fail in IE6. For IE6, you need to apply an event model other than the W3C one, and this is why we use libraries for these tricks.


The benefits of this approach are more than just being able to use a single event handler. Say, for example, you want to add more links dynamically to this list. With event delegation, there is no need to change anything; with simple event handling, you would have to reassign handlers and re-loop the list.


Anonymous Functions And The Module Pattern 匿名函数和模块化

One of the most annoying things about JavaScript is that it has no scope for variables. Any variable, function, array or object you define that is not inside another function is global, which means that other scripts on the same page can access—and will usually override— them.


The workaround is to encapsulate your variables in an anonymous function and call that function immediately after you define it. For example, the following definition would result in three global variables and two global functions:


var name = 'Chris';
var age = '34';
var status = 'single';
function createMember(){
  // [...]
function getMemberDetails(){
  // [...]

Any other script on the page that has a variable named status could cause trouble. If we wrap all of this in a name such as myApplication, then we work around that issue:

如果这个页面上的其它脚本里也存在一个叫 status 的变量,麻烦就会出现。如果我们把它们封装在一个 myApplication 里,这个问题就迎刃而解了:

var myApplication = function(){
  var name = 'Chris';
  var age = '34';
  var status = 'single';
  function createMember(){
    // [...]
  function getMemberDetails(){
    // [...]

This, however, doesn't do anything outside of that function. If this is what you need, then great. You may as well discard the name then:


  var name = 'Chris';
  var age = '34';
  var status = 'single';
  function createMember(){
    // [...]
  function getMemberDetails(){
    // [...]

If you need to make some of the things reachable to the outside, then you need to change this. In order to reach createMember() or getMemberDetails(), you need to return them to the outside world to make them properties of myApplication:

如果你想在函数外面也能使用里面的东西,那就要做些修改。为了能访问 createMember() 或 getMemberDetails(),你需要把它们变成 myApplication的属性,从而把它们暴露于外部的世界:

var myApplication = function(){
  var name = 'Chris';
  var age = '34';
  var status = 'single';
      // [...]
      // [...]
// myApplication.createMember() and
// myApplication.getMemberDetails() now works.

This is called a module pattern or singleton. It was mentioned a lot by Douglas Crockford and is used very much in the Yahoo User Interface Library YUI. What ails me about this is that I need to switch syntaxes to make functions or variables available to the outside world. Furthermore, if I want to call one method from another, I have to call it preceded by the myApplication name. So instead, I prefer simply to return pointers to the elements that I want to make public. This even allows me to shorten the names for outside use:

这被称作 module 模式或 singleton。Douglas Crockford 多次谈到过这些,Yahoo User Interface Library YUI 里对此有大量的使用。但这样一来让我感到不便的是,我需要改变句式来使函数和变量能被外界访问。更甚者,调用时我还需要加上myApplication 这个前缀。所以,我不喜欢这样做,我更愿意简单的把需要能被外界访问的元素的指针导出来。这样做后,反倒简化了外界调用的写法:

var myApplication = function(){
  var name = 'Chris';
  var age = '34';
  var status = 'single';
  function createMember(){
    // [...]
  function getMemberDetails(){
    // [...]
//myApplication.get() and myApplication.create() now work.

I've called this "revealing module pattern."

我把这个称作 “revealing module pattern.”

Allowing For Configuration 可配置化

Whenever I've written JavaScript and given it to the world, people have changed it, usually when they wanted it to do things that it couldn't do out of the box—but also often because I made it too hard for people to change things.


The workaround is to add configuration objects to your scripts. I've written about JavaScript configuration objects in detail, but here's the gist:


  • Have an object as part of your whole script called configuration.
  • In it, store all of the things that people will likely change when they use your script:
    • CSS ID and class names;
    • Strings (such as labels) for generated buttons;
    • Values such as "number of images being displayed," "dimensions of map";
    • Location, locale and language settings.
  • Return the object as a public property so that people can override it.
  • 在你的脚本了添加一个叫做 configuration 的对象。
  • 这个对象里面,存放所有人们在使用这个脚本时经常要改动的东西:
    • CSS ID 和类名称;
    • 按钮的名称,标签字等;
    • 诸如”每页显示图片数”的值, “图像的显示的尺寸”的值;
    • 地点,位置,以及语言设置。
  • 将这个对象作为一个公用属性返回给用户,这样用户可以修改覆盖它。

Most of the time you can do this as a last step in the coding process. I've put together an example in "Five things to do to a script before handing it over to the next developer."

通常情况下这是你编程过程中的最后一步要做的事情。我把这些集中表现在了一个例子里: “Five things to do to a script before handing it over to the next developer.”

In essence, you want to make it easy for people to use your code and alter it to their needs. If you do that, you are much less likely to get confusing emails from people who complain about your scripts and refer to changes that someone else actually did.


Interacting With The Back End 与后台交互

One of the main things I learned from all my years with JavaScript is that it is a great language with which to make interactive interfaces, but when it comes to crunching numbers and accessing data sources, it can be daunting.


Originally, I learned JavaScript to replace Perl because I was sick of copying things to a cgi-bin folder in order to make it work. Later on, I learned that making a back-end language do the main data churning for me, instead of trying to do all in JavaScript, makes more sense with regard to security and language.

最初,我学习JavaScript,是用来替代Perl的,因为我很讨厌非要把代码拷贝到 cgi-bin 文件夹下才能使Perl运行。后来,我明白了应该使用一种后台工作的语言来处理主要的数据,而不能什么事情都让JavaScript去做。更重要的是我们要考虑安全性和语言特征。

If I access a Web service, I could get JSON-P as the returned format and do a lot of data conversion on the client, but why should I when I have a server that has a richer way of converting data and that can return the data as JSON or HTML… and cache it for me to boot?

如果我访问一个Web service, 我可以获取到JSON-P 格式的数据,在客户端浏览器里我把它做各种各样的数据转换,但当我有了服务器时,我有了更多的方法来转换数据,我可以在Server端生成JSON或HTML格式的数据返回给客户端,以及缓存数据等操作。

So, if you want to use AJAX, learn about HTTP and about writing your own caching and conversion proxy. You will save a lot of time and nerves in the long run.


Browser-Specific Code Is A Waste Of Time. Use Libraries! 编写适用各种浏览器的程序是种浪费时间,使用工具包吧!

When I started Web development, the battle between using document.all and using document.layers as the main way to access the document was still raging. I chose document.layers because I liked the idea of any layer being its own document (and I had written more than enough document.write solutions to last a lifetime). The layer model failed, but so did document.all. When Netscape 6 went all out supporting only the W3C DOM model, I loved it, but end users didn't care. End users just saw that this browser didn't show the majority of the Internets correctly (although it did)—the code we produced was what was wrong. We built short-sighted code that supported a state-of-the-art environment, and the funny thing about the state of the art is that it is constantly changing.

在我最初开始搞Web开发时,在访问页面时,究竟是使用 document.all 还是使用 document.layers 的问题上痛苦的挣扎了很久。我选择了 document.layers,因为我喜欢任何层都是自己的document的思想 (而且我写了太多的 document.write 来生成元素)。层模式最终失败了,于是我开始使用 document.all。当Netscape 6 公布只支持 W3C DOM 模型时,我很高兴,但其实用户并不关心这些。用户只是看见这种浏览器不能显示大多数浏览器都能正常显示的东西—这是我们编码的问题。我们编写了短视的代码,只能运行在当前的环境下,而不幸的是,我们的运行环境却在不停的改变。

I've wasted quite some time learning the ins and outs of all of the browsers and working around their issues. Doing this back then secured my career and ensured that I had a great job. But we shouldn't have to go through this trial by fire any longer.


Libraries such as YUI, jQuery and Dojo are here to help us with this. They take on the problems of browsers by abstracting the pains of poor implementation, inconsistencies and flat-out bugs, and relieve us of the chore. Unless you want to beta test a certain browser because you're a big fan, don't fix browser issues in your JavaScript solutions, because you are unlikely to ever update the code to remove this fix. All you would be doing is adding to the already massive pile of outdated code on the Web.

一些工具包,例如 YUI, jQuery 以及 Dojo 都能够帮我们处理这类问题。它们通过抽象各种接口实现来处理浏览器的各种问题,像版本不兼容,设计缺陷等,把我们从痛苦中解救出来。除非你要测试某个Beta版的浏览器,千万不要在自己的程序里添加修正浏览器的缺陷的代码,因为你很有可能当浏览器已经修改了这个问题时,你却忘了删除你的代码。

That said, relying solely on libraries for your core skill is short-sighted. Read up on JavaScript, watch some good videos and tutorials on it, and understand the language. (Tip: closures are God's gift to the JavaScript developer.) Libraries will help you build things quickly, but if you assign a lot of events and effects and need to add a class to every HTML element in the document, then you are doing it wrong.






小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏






《PHP经典实例(第2版)》 斯克拉(David Sklar) (作者), 切贝特伯格(Adam Tracbtenberg) (作者), 李松峰 (译者), 秦绪文 (译者), 李丽 (译者)