这一章可谓本书的核心章节之一。作者不仅介绍了很多实用的技术,更阐明了在 Scripting 编程方面的一些核心理念。学东西,一方面是表面上的规定和技巧,另一方面就是技巧背后的思想了。掌握了这些核心思想,我想在其他领域也可以得到验证和应用。
一、过去的错误
作者首先提到了在过去几年里,人们对 JS 的误用造成的不必要的误解。很多网页设计师不愿意去学习 JS,而是仅仅把一些现成的代码片段拿来用,以实现某个特定的功能。他们并没有考虑假如 JS 被禁用,他们的网站还能够正常展现吗?你可能会有疑问,难道还有人手动禁用浏览器的 JS 功能?呵呵,这种人或许很少,但是有一种生物——网络爬虫,它们是不能识别 JS 的,而仅仅只能读懂 HTML 语言。因此,从搜索引擎,或者说 web 信息收集工具的可访问性(accessible)角度来说,很多人认为 JS 就是 inaccessible 的代名词。
作者接着举出 Flash 的例子,并提出了 “没有不好的技术,只有对技术的拙劣使用” 的看法,说明并非 JS 不好,而是对 JS 的滥用造成了对其的负面影响。他提出了建议,当你打算用 JS 实现网页的某项功能时,问自己两个问题(1)这项功能是否必要(2)这项功能是否影响到了用户体验。回答了这两个问题,我想接下来你所作的决定,一定是明智的。
二、优雅降级(Graceful degradation)
什么是优雅降级?
“优雅降级(Graceful degradation)是指电脑,机器,电子系统或者是网络在本身大部分已经毁坏或无效的情况下还能保持有限的功能这种能力。优雅降级的目的是阻止灾难性的失败。理想情况下,有优雅降级特征的系统即使多个组件同时失效也不会引起停机。在优雅降级中,操作的效率和速度随着失效部件的增加逐渐下降。”
对于 JS 来说,就是当 JS 不起作用时,网页在一定程度上是可以访问的,这就保证了没有 JS 只有 HTML 的页面也能维持大部分的正常功能。这样一来,你的网站对网络爬虫更加友好,在一定程度上可以增加搜索引擎中的排名。
作者举出了一个实例,假如你需要在点击一个 <a> 标签之后弹出一个窗口,你可以这么干:
<script type="text/javascript"> function popUp(winURL) { window.open(winURL,"popup","width=320,height=480"); } </script> <a href="#" onclick="popUp('http://www.example.com/');return false;">Example<a>
但如果网络爬虫遇到这儿,它不懂 onclick,那怎么知道这个 <a> 到底是想要链接到哪?可以这么干:
<a href="http://www.example.com/" onclick="popUp(this.href; return false;">Example</a>
三、来自 CSS 的启示
作者大赞 CSS,因为它实现了将网页文档的结构(structure)和设计(design)分离的效果。他认为这种思想同样可以运用到 JS 上来,使 JS 实现将网页文档的结构(structure)和行为(behavior)分离的效果。如下图所示:
HTML 语言撑起了网页内容的结构,它代表了结构层(Structure Layer),它是网页的核心层;然后我们把 JS 和 CSS 分别看成行为层(Behavior Layer)和 表现层(Presentation Layer)。它们都是以结构层为基础,以一种插件的形式附加上去的。
将 BL 和 PL 逐渐附加到 SL 的过程叫 渐进增强(progressive enhancement)。当然,以这种渐进增强的形式构建起的网页,同时也是可以优雅降级(Graceful degradation)的。
四、非入侵式 JS(Unobtrusive JavaScript )
通俗一点说,非入侵式 JS 的意思就是在给 HTML 标签附加 JS 触发函数时,不要用内联属性的方式实现,而尽量在外部将事件处理函数附加给元素,多说无益,看代码:
入侵式的做法:
<button onclick="popup("www.baid.com");"> Popup </button>
其中,函数 pupup() 定义在 <head> 部分或外部 js 文件中,这样以保证在事件触发时所要调用的 js 文件全部加载完毕。
非入侵的做法:
<button id="btn"> Popup </button> <script type="text/javascript"> window.onload = function(){ document.getElementById("btn").onclick = function(){ popup("www.baidu.com"); } } </script>
感觉到不同没有?前者是固定的、僵死的、入侵式的,而后者是动态的、灵活的、低调的。
再说明一点,后者的 <script> 部分应该放在哪?放在外部 js 文件 或 <head> 中?都不会起作用,因为这样一来这段代码就不会自动运行了,而我们要求遇到这段代码就立即执行,所以是应该放在 <body> 中了。(关于 <script> 的不同位置所起到的不同效果,可参考 W3CSchool 的 解释)。
五、向后兼容性(Backward compatibility )
什么是向后兼容性?要知道,即使浏览器支持 JS,支持的力度也是不同的。低版本的浏览器仅支持某一部分 JS 功能。因此,在为网站添加 JS 代码时,需要考虑对旧浏览器的兼容。作者推荐了一种很流行的解决方法:对象检测(Object detection )。实现方法如下:
if (method) {
statements
}
举个具体例子吧:
function myFunction() {
if (document.getElementById) {
statements using getElementById
}
}
只要浏览器不识别此 method,就会返回 false,自然就不执行后面的语句了。不过这样有个问题:那岂不是每用一次方法,都要做出判断?呵呵,换一种角度吧,从“如果支持,则执行” 到 “如果不支持,则退出”,这样就优雅地解决了问题,如下:
// 在 js 代码最开始的地方
if (!getElementById) {
returnfalse;
}
就这样,你需要验证什么函数,就把它们的判断集中起来放在代码的最前面,一旦不支持立马撤,这样效率就高多了!
六、性能方面的注意事项
如果一个网页因为 js 而导致浏览速度奇慢,那就得不偿失了。作者给出了关于性能的几点建议:
减少对 DOM 的查询次数
看下面一段:
if (document.getElementsByTagName("a").length >0) {
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
// do something to each link.
}
}
是不是 document.getElementById 重复执行了两次?解决方法就是,使用变量做好缓存:
var links = document.getElementsByTagName("a");
if (links.length >0) {
for (var i=0; i<links.length; i++) {
// do something to each link.
}
}
脚本的聚合与放置
脚本的聚合很简单,如果你引入了多个 js 文件,不妨把它们放一起再引用。
脚本的放置则关心到页面的初始化速度了。如果按惯例放在 <head> 中,那么在浏览器加载页面时,首先会加载 js 文件,在这个时间里是不会同时加载 <body> 部分的。这样就可能需要很长的初始化时间,而页面的其他元素(如图像)就得不到第一时间的加载,这样会影响到用户体验。
所以我们可以把在 <head> 部分声明的所有 <script> 标签全部迁移到 <body> 中,而且是在 </body> 的前面。就这么简单的做法,可以很大程度上提升页面的初始化体验。
缩小脚本文件大小
这个相信大家不陌生。使用一些压缩工具,把 JS 脚本文件中的空格、注释全部去掉,这样就可以大大减小脚本文件的大小了,相应会提升脚本的载入速度。这种压缩工具网上很多,一搜一大把~
本章介绍了 JS 编程中的一些核心概念,非常重要。下一章中,我们会利用这些思想,来改进之前所编写的 Image Gallery。
转载于:http://www.cnblogs.com/hustlzp/archive/2011/08/11/the-reading-note-of-the-book-DOM-Scripting.html