对象的简写
在过去,若是你想建立一个对象,你须要这样:html
var car = new Object(); car.colour = 'red'; car.wheels = 4; car.hubcaps = 'spinning'; car.age = 4;
下面的写法可以达到一样的效果:node
var car = { colour:'red', wheels:4, hubcaps:'spinning', age:4 }
这样就简单多了,你不须要反复使用这个对象的名称。
这样 car 就定义好了,也许你会遇到 invalidUserInSession 的问题,这只有你在使用IE时会碰到,只要记住一点,不要右大括号前面写分号,你就不会有麻烦。shell
数组的简写编程
传统的定义数组的方法是这样:json
var moviesThatNeedBetterWriters = new Array( 'Transformers','Transformers2','Avatar','Indiana Jones 4');
简写版是这样:数组
var moviesThatNeedBetterWriters = [ 'Transformers','Transformers2','Avatar','Indiana Jones 4'];
对于数组,这里有个问题,其实没有什么图组功能。但你会常常发现有人这样定义上面的 car ,就像这样:浏览器
var car = new Array(); car['colour'] = 'red'; car['wheels'] = 4; car['hubcaps'] = 'spinning'; car['age'] = 4;
数组不是万能的;这样写不对,会让人困惑。图组其实是对象的功能,人们混淆了这两个概念。缓存
三元条件符号的简写安全
另一个很是酷的简写方法是使用与三元条件符号。
你没必要写成下面的样子:服务器
var direction; if(x < 200){ direction = 1; } else { direction = -1; }
你可使用三元条件符号简化它:
var direction = x < 200 ? 1 : -1;
当条件为true
时取问号后面的值,不然取冒号后面的值。
Douglas Crockford 发明了JSON 以后,一切全变了。
使用JSON,你可使用JavaScript自有功能把数据存贮成复杂的格式,并且不须要再作其它的额外转换,直接能够访问使用。
JSON 是 “JavaScript Object Notation” 的缩写,它用到了上面提到的两种简写方法。
若是你想描述一个乐队,你可能会像这样写:
var band = { "name":"The Red Hot Chili Peppers", "members": [ { "name":"Anthony Kiedis", "role":"lead vocals" }, { "name":"Michael 'Flea' Balzary", "role":"bass guitar, trumpet, backing vocals" }, { "name":"Chad Smith", "role":"drums,percussion" }, { "name":"John Frusciante", "role":"Lead Guitar" } ], "year":"2009" }
你能够在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> <script src="#"></script>
这是调用 Delicious 网站提供的 Web service 功能,得到JSON格式的最近的无序书签列表。
基本上,JSON是最轻便的描述复杂数据结构的方法,并且它能在浏览器里运行。你甚至能够在PHP里用 json_decode() 函数来运行它。
JavaScript里的math和String函数后,发现它们能极大的简化个人编程劳动。使用它们,你能够省去复杂的循环处理和条件判断。
例如,当须要实现一个功能,找出数字数组里最大的一个数时,我过去是这样写出这个循环的,就像下面:
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]; } } alert(max);
不用循环也能实现:
var numbers = [3,342,23,22,124]; numbers.sort(function(a,b){ return b - a }); alert(numbers[0]);
Web应用都是由事件驱动运转的。我喜欢事件处理,尤为喜欢本身定义事件。
它能使你的产品可扩展,而不用改动核心代码。
有一个很大的问题(也能够说是功能强大的表现),是关于页面上事件的移除问题。你能够对某个元素安装一个事件监听器,事件监听器就开始运转工做。
但页面上没有任何指示说明这有个监听器。由于这种不可表现的问题 (这尤为让一些新手头疼) ,以及像IE6这样的”浏览器“在太多的使用事件监听时会出现各类的内存问题,你不得不认可尽可能少使用事件编程是个明智的作法。
因而事件委托就出现了。
当页面上某个元素上的事件触发时,而在 DOM 继承关系上,这个元素的全部子元素也能接收到这个事件,这时你可使用一个在父元素上的事件处理器来处理,而不是使用一堆的各个子元素上的事件监听器来处理。
到底是什么意思?这样说吧,页面上有不少超连接,你不想直接使用这些连接,想经过一个函数来调用这个连接,HTML代码是这样的:
<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> </ul>
常见的作法是经过循环这些连接,将每一个连接上附加一个事件处理器:
(function(){ 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 links[i].addEventListener('click',handler,false); }; function handler(e) { var x = e.target; // Get the link that was clicked alert(x); e.preventDefault(); }; })();
咱们用一个事件处理器也能完成这项任务:
(function(){ var resources = document.getElementById('resources'); resources.addEventListener('click',handler,false); function handler(e) { var x = e.target; // get the link tha if(x.nodeName.toLowerCase()== 'a') { alert('Event delegation:' + x); e.preventDefault(); } }; })();
由于点击事件就发生在这些页面元素里,你要作的就是比较它们的 nodeName
,找出应该回应这个事件的那个元素。
免责声明:上面说的这两个关于事件的例子,在全部浏览器里都能运行,除了IE6,在IE6上你须要使用一个事件模型,而不是简单的W3C的标准实现。这也就是咱们推荐使用一些工具包的缘由。
这种方法的好处并非仅限于把多个事件处理器缩减为一个。你想一想,举个例子,你须要动态的往这个连接表里追加更多的连接。使用事件委托后,你就不须要作其它修改了;不然的话,你须要从新循环这个连接表,从新给每一个连接安装事件处理器。
在JavaScript里最使人懊恼的事情是变量没有使用范围。任何变量,函数,数组,对象,只要不在函数内部,都被认为是全局的,这就是说,这个页面上的其它脚本也能够访问它,并且能够覆盖重写它。
解决办法是,把你的变量放在一个匿名函数内部,定义完以后当即调用它。
例如,下面的写法将会产生三个全局变量和两个全局函数:
var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] }
若是这个页面上的其它脚本里也存在一个叫 status
的变量,麻烦就会出现。
若是咱们把它们封装在一个 myApplication
里,这个问题就迎刃而解了:
可是,这样一来,在函数外面就没有什么功能了。若是这是你须要的,那就能够了。
你还能够省去函数的名称:
(function(){ var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } })();
若是你想在函数外面也能使用里面的东西,那就要作些修改。
为了能访问 createMember() 或 getMemberDetails(),你须要把它们变成 myApplication的属性,从而把它们暴露于外部的世界:
var myApplication = function() { var name = 'Chris'; var age = '34'; var status = 'single'; return{ createMember:function(){ // [...] }, getMemberDetails:function(){ // [...] } } }();
这被称做 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(){ // [...] } return{ create:createMember, get:getMemberDetails } }();
我把这个称做 “revealing module pattern.”
一旦我把所写的JavaScript代码发布到这个世界上,就有人想改动它,一般是人们想让它完成一些它自己完成不了的任务—但一般也是我写的程序不够灵活,没有提供用户可自定义的功能。
一般状况下这是你编程过程当中的最后一步要作的事情。我把这些集中表如今了一个例子里: “Five things to do to a script before handing it over to the next developer.”
实际上,你也但愿你的代码可以让人们很方面的使用,而且根据他们各自的须要进行一些改动。
若是你实现了这个功能,你会少收到一些抱怨你的脚本的人发送给你的让你困惑的邮件,这些信件会告诉你,有人修改了你的脚本,并且很好用。
在这么多年的编程经历中,我所领悟到的一个重要的事情就是,JavaScript是一个很优秀的开发界面交互的语言,但若是用来处理数字或访问数据源,那就有点使不上劲了。
最初,我学习JavaScript,是用来替代Perl的,由于我很讨厌非要把代码拷贝到 cgi-bin
文件夹下才能使Perl运行。
后来,我明白了应该使用一种后台工做的语言来处理主要的数据,而不能什么事情都让JavaScript去作。更重要的是咱们要考虑安全性和语言特征。
若是我访问一个Web service, 我能够获取到JSON-P 格式的数据,在客户端浏览器里我把它作各类各样的数据转换,但当我有了服务器时,我有了更多的方法来转换数据,我能够在Server端生成JSON或HTML格式的数据返回给客户端,以及缓存数据等操做。
若是你事先了解了并准备了这些,你会长期收益,省去了不少头疼的时间。
在我最初开始搞Web开发时,在访问页面时,到底是使用 document.all
仍是使用 document.layers
的问题上痛苦的挣扎了好久。
我选择了 document.layers
,由于我喜欢任何层都是本身的document的思想 (并且我写了太多的 document.write
来生成元素)。
层模式最终失败了,因而我开始使用 document.all
。
当Netscape 6 公布只支持 W3C DOM 模型时,我很高兴,但其实用户并不关心这些。
用户只是看见这种浏览器不能显示大多数浏览器都能正常显示的东西—这是咱们编码的问题。
咱们编写了短视的代码,只能运行在当前的环境下,而不幸的是,咱们的运行环境却在不停的改变。
我已经浪费了太多的时间来处理对各类浏览器各类版本兼容的问题。
善于处理这类问题提供了我一个好的工做机会。但如今咱们没必要在忍受这种痛苦了。
一些工具包,例如 YUI, jQuery 以及 Dojo 都可以帮咱们处理这类问题。
它们经过抽象各类接口实现来处理浏览器的各类问题,像版本不兼容,设计缺陷等,把咱们从痛苦中解救出来。
除非你要测试某个Beta版的浏览器,千万不要在本身的程序里添加修正浏览器的缺陷的代码,由于你颇有可能当浏览器已经修改了这个问题时,你却忘了删除你的代码。
另外一方面,彻底依赖于工具包也是个短视的行为。工具包能够帮你快速的开发,但若是你不深刻理解JavaScript,你也会作错事。