3

客户端检测

不到万不得已,就不要使用客户端检测。只要能够找到更通用的方法,就应该优先采用更通用的方法。先设计最通用的方案,然后再使用特定于浏览器的技术增强该方案。

能力检测(性能检测)

基本模式语法

目标不是识别特定的浏览器,而是识别浏览器的能力。基本模式如下:

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 !");
    }
}

能力检测使用的要点

  1. 先检测达成目的的最常用的特性,可以保证代码最优化,并避免检测多个条件;

  2. 必须测试实际要是用到的特性;

对于第二点:

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 的实例。


JS菌
6.4k 声望2k 粉丝