客户端检测
不到万不得已,就不要使用客户端检测。只要能够找到更通用的方法,就应该优先采用更通用的方法。先设计最通用的方案,然后再使用特定于浏览器的技术增强该方案。
能力检测(性能检测)
基本模式语法
目标不是识别特定的浏览器,而是识别浏览器的能力。基本模式如下:
if (object.propertyInQuestion){
//使用object.propertyInQuestion
}
举个例子,比如 IE5.0 之前的版本不支持 document.getElementById() 这个 DOM 方法。但可以使用 document.all[] 方法。于是可以写下如下代码:
function getElement(id){
if (document.getElementById){
return document.getElementById(id);
}else if (document.getAll){
return document.getAll[id];
}else{
throw new Erroor("No way to retrieve element !");
}
}
能力检测使用的要点
先检测达成目的的最常用的特性,可以保证代码最优化,并避免检测多个条件;
必须测试实际要是用到的特性;
对于第二点:
function getWindowWidth(){
if (document.all){ //假设是 IE 浏览器
return document.documentElement.clientWidth; //错误!不一定是 IE 浏览器
} else {
return window.innerWidth;
}
}
如Opera 支持document.all,也支持window.innerWidth;所以上述代码用法上有问题。
更可靠的能力检测
能力检测对于想知道某个特性是否会按照适当方式行事非常有用。如检测对象是否支持排序:
function isSortable(obj){
return typeof obj.sort == "function";
}
var obj1 = [321,43215,1];
var obj2 = {
name: "Oliver",
age: 18
};
console.log(isSortable(obj1)); //true
console.log(isSortable(obj2)); /false
这里需要注意的是,能力检测不是只检测相应的方法是否存在!!!
function isSortable(obj){
return !!obj.sort;
}
var obj1 = [321,43215,1];
var obj2 = {
name: "Oliver",
age: 18,
sort: true
};
console.log(isSortable(obj1)); //true
console.log(isSortable(obj2)); //true
这里就可以看出问题了,能力检测不是检测相应的方法是否存在,obj2 中定义了 sort 属性,仍然可以通过所谓的能力检测检测为 true。
所以在可能的情况下,要尽量使用 typeof
进行能力检测。
而在 IE 中,情况又不同了:
function hasCreateElement(){
return typeof document.createElement == "function";
}
在 IE8 之前,这个函数返回 false,因为 typeof document.createElement 返回的是"object",而不是“function”。因为 IE 及更早版本中的宿主对象是通过 COM 而非 JScript 实现的。但 IE9 中纠正了这个问题,对所有 DOM 方法都返回“function”。
能力检测,不是浏览器检测
在实际开发中,应该将能力检测作为确定下一步解决方案的依据,而不是用他来判断用户使用的是什么浏览器。如:
var hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);
var hasDOM1 = !!(document.getElementById && document.getElementsByTagName && document.createElement);
上述代码一个是用来确定浏览器是否支持 Netscapte 风格的插件;另一个是用来确定浏览器是否具备 DOM1 级所规定的能力。
怪癖检测
目标是识别浏览器的特殊行为。怪癖检测是想要知道浏览器存在什么缺陷。如,IE8 及更早版本中存在一个 bug,即如果某个实例属性与[[Enumerable]]标记为 false 的某个原型属性同名,那么该实例就不会出现在 for-in 循环当中。可以使用以下代码来检测这种“怪癖”:
var hasDontEnumQuirk = function(){
var o = { toString : function(){} };
for (var prop in o){
if (prop == "toString"){
return false;
}
}
return true;
}();
另外,在 Safari 3 以前的版本中会枚举被隐藏的属性。可以用下面的函数来检测:
var hasEnumShadowsQuirk = function(){
var o = { toString : function(){} }
var count = 0;
for (var prop in o){
if (prop == "toString"){
count++;
}
}
return (count > 1);
}();
如果浏览器存在这个 bug,那么使用 for-in 循环枚举带有自定义的 toString() 方法的对象,就会返回两个 toString 的实例。