第3章 浏览器
每种浏览器都包含一个代码引擎或渲染引擎,它负责解释Web页面上的代码,javascript解释器是其中的一部分。
Netscape4惨败之后,网景公司于1998年创立了Mozilla项目,开发了Gecko引擎,现在它支持着Mozilla, Firefox, Netscape, Camino等浏览器。
Explorer的代码引擎叫做Trident,1999年3月发布的Explorer5.0是第一个支持W3C DOM和XMLHttpRequest的浏览器,但也是最后一个包含了主要Javascript更新的Explorer版本。
Safari于2003年发布,它使用KHTML代码引擎,它是Macintosh平台的默认浏览器。
Opera是一个独立的浏览器,在浏览器大战期间,它没有实现DHTML,现在看来,这是一个相当英明的决定。
4种兼容性问题
不支持:这些出现问题的功能不是“不可或缺”的基础功能,都能够通过对象检测判断,而且浏览器也在努力消除这些问题,如document.sytleSheets来读写整个样式表,目前Safari和Opera也增加了对其的支持。
合理的不同看法:如defer属性对加载脚本的要求,Exploer有独特的理解,幸好这种问题是最少有的。
有意为之的兼容性问题:通常是浏览器大战的遗留问题,也可以通过对象检测来判断,一旦微软着手实现W3C事件标准,最后一批被故意造成的兼容性问题也将得到解决。
浏览器bug:这是由于编程的缺陷造成的不可预见的错误,它是无法解决也是无法衡量的。如Exploer6会被normalize()方法导致崩溃。
浏览器兼容性问题是单纯的生活的事实,它不会轻易消失,应该尽快地习惯它,至少听任它。
在任何情况下都不要先为某一个浏览器写脚本,然后增加其他浏览器的支持。在项目支出就应该解决这些兼容性问题,而不是放在最后。
对象检测
对象检测是避免兼容性问题的最佳助手。它的一般方法是检查想使用的对象,看它们是否存在,如果不存在,就结束函数。(if(!对象)),从技术上说,对象检测是把一个对象转换成一个布尔值。
检查W3C DOM:
var W3CDOM = document.createElement && document.getElementsByTagName;
对W3C DOM的检测使我们可以总是假设浏览器也支持相关的功能,如appendChild,而省去对它的检查。
事件处理测试:
function addEventSimple(obj, evt, fn) {
if (obj.addEventListener) //W3C
obj.addEventListener(evt, fn, false);
else if (obj.attachEvent) //微软
obj.attachEvent('on' + evt, fn);
}
我们期望未来的版本使用标准,所以对标准的支持应该最先检查,事实上先检查attachEvent,Fx等浏览器会报错。
浏览器检测
为什么浏览器检测行不通?浏览器兼容性模式是不断变化的,今天不支持的属性,明天可能会支持;而且浏览器常常会伪装自己的身份,以便通过浏览器检测。
浏览器检测的军备竞赛
navigator.userAgent中保存了每一个浏览器的识别字符串。1995年前后的Mosaic和Netscape年代中,由于
Netscape的cookie和<center>标签等的支持,服务器端的程序员决定使用浏览器检测来区分两种浏览器,他们检测识别字符串
是否从Mozilla/开始,这给javascript世界带来了不必要的磨难。浏览器厂商被迫将自己的识别字符串变成从Mozilla/开始,即便是
Explorer最初进入市场时也将自己伪装成了Netscape。浏览器大战开始后,Web开发者们做出反应,他们创建了更多的浏览器程序来区分
Netscape和Exploer,而当战争结束时,已经有数不清的网站设置了检测脚本只允许Explorer访问,历史重演了,一些浏览器如
Opera,又不得不修改自己的识别字符串来匹配Explorer,甚至将识别字符串的设置开放给用户。
拆解浏览器字符串
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)
第一个是Mozilla1.7.12,第二个是NT5.1(即XP)的Explorer6.0,第三个是Safari1.3.2,第四个是伪装后的Safari1.3.2。
userAgent:使用navigator.userAgent,而不是navigator.appName和navigator.appVersion。前者尚有一些遵循,后者都是谎言;
Mozilla/:只能证明浏览器是1994年后发布的;
/[version number]:没有意义,每一个现代浏览器都生命是第4版或第5版的Mozilla;
不规则字符串:通常被圆括号包围,包含这非常复杂的缩写;
Opera:唯一支持window.opera属性,可以检测这个对象来判断;
Safari, iCab和Konqueror:不像Opera那样勇于承担风险,它们可以完全地伪装自己;
Gecko:Mozilla识别串通常都会包含Gecko,但不幸Safari等也包含;
MSIE:没有意义,绝大多数的浏览器都包含MSIE;
版本号:Exploer和Opera允许在名字后面找到自己的版本号,而其他浏览器都无效,比如Mozilla的隐藏版本;
操作系统:Windows操作系统都以Win开始,当然这不适用于伪装的串。
(http://www.quirksmode.org/js/detect.html)
浏览器检测的正确使用
当你需要知道访问者的浏览器,如站点统计时,这些检测不会影响脚本逻辑。
当我们用对象检测时需要排除浏览器bug等时,可以将对象检测和浏览器检测一起使用。
调试
Mozilla有最好的错误信息,因此多在Mozilla中调试;
使用return,alert,confirm是不错的方法,复杂的调试可以自己创建一个错误控制台;
将bug报告给浏览器厂商。