您当前的位置:首页 > 网站建设笔记 >

javascript能力检测(识别浏览器的能力)

0

能力检测

最常用也最为人们广泛接受的客户端检测形式是能力检测(又称特性检测)。能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。采用这种方式不必顾及特定的浏览器如何如何,只要确定浏览器支持特定的能力,就可以给出解决方案。能力检测的基本模式如下:

if(object.propertyInQuestion){
}

举例来说,IE5.0之前的版本不支持document.getElementById()这个DOM方法。尽管可以使用非标准的document.all属性实现相同的目的,但IE的早期版本中确实不存在document.getElementById()。于是,也就有了类似下面的能力检测代码:

function getElement(id){
	if(document.getElementById){
		return document.getElementById(id);
	}else if(document.all){
		return document.all[id];
	}else{
		throw new Error("No way to retrieve element!");
	}
}

这里的getElement()函数的用途是返回具有给定ID的元素。因为document.getElementById()是实现这一目的的标准方式,所以一开始就测试了这个方法。如果该函数存在(不是未定义),则使用该函数。否则,就要继续检测document.all是否存在,如果是,则使用它。如果上述两个特性都不存在,则创建并抛出错误,表示这个函数无法使用。要理解能力检测,首先必须理解两个重要的概念。如前所述,第一个概念就是先检测达成目的的最常用的特性。对前面的例子来说,就是要先检测document.getElementById(),后检测document.all。先检测最常用的特性可以保证代码最优化,因为在多数情况下都可以避免测试多个条件。第二个重要的概念就是必须测试实际要用到的特性。一个特性存在,不一定意味着另一个特性也存在。来看一个例子:

function getWindowWidth(){
	if(document.all){
		return document.documentElement.clientWidth;
	}else{
		return window.innerWidth;
	}
}

这是一个错误使用能力检测的例子。getWindowWidth()函数首先检查document.all是否存在,如果是则返回document.documentElement.clientWidth。IE8及之前版本确实不支持window.innerWidth属性。但问题是document.all存在也不一定表示浏览器就是IE。实际上也可能是Opera,Opera支持document.all也支持window.innerWidth。

更可靠的能力检测

能力检测对于想知道某个特性是否会按照适当方式行事(而不仅仅是某个特性存在)非常有用。上一节中的例子利用类型转换来确定某个对象成员是否存在,但这样你还是不知道该成员是不是你想要的。来看下面的函数,它用来确定一个对象是否支持排序。

//不要这样做!这不是能力检测,只是检测了是否存在相应的方法
function isSortable(object){
	return !!object.sort;
}

这个函数通过检测对象是否存在sort()方法,来确定对象是否支持排序。问题是任何包含sort属性的对象也会返回true。
var result = isSortable({sort:true});
检测某个属性是否存在并不能确定对象是否支持排序。更好的方式是检测sort是不是一个函数。

function isSortable(object){
	return typeof object.sort == "function";
}

这里的typeof操作符用于确定sort的确是一个函数,因此可以调用它对数据进行排序。在可能的情况下,要尽量使用typeof进行能力检测。特别是,宿主对象没有义务让typeof返回合理的值。最令人发指的事儿就发生在IE中。大多数浏览器在检测到document.createElement()存在时,都会返回true。

//IE8及之前版本中不行
function hasCreateElement(){
	return typeof document.createElement == "function";
}

在IE8及之前版本中,这个函数返回false,因为typeof document.createElement返回的是"object",而不是"function"。如前所述,DOM对象是宿主对象,IE及更早版本中的宿主对象是通过COM而非JScript实现的。因此,document.createElement()函数确实是一个COM对象,所以typeof才会返回"object"。IE9纠正了这个问题,对所有DOM方法都返回"function"。关于typeof的行为不标准,IE中还可以举出例子来。ActiveX对象(只有IE支持)与其他对象的行为差异很大。例如,不使用typeof测试某个属性会导致错误,如下所示。

//在IE中会导致错误
var xhr = new ActiveXObject("Microsoft.XMLHttp");
if(xhr.open){	//这里发生错误
	//执行操作
}

像这样直接把函数作为属性访问会导致JavaScript错误。使用typeof操作符会更靠谱一点,但IE对typeof xhr.open会返回"unknoww"。这就意味着,在浏览器环境下测试任何对象的某个特性是否存在,要使用下面这个函数。

function isHostMethod(object, property){
	var t = typeof object[property];
	return t == "function" || (!!(t=="object" && object[property])) || t=="unknown";
}

可以像下面这样使用这个函数:

result = isHostMethod(xhr, "open");	//true
result = isHostMethod(xhr, "foo");	//false

目前使用isHostMethod()方法还是比较可靠的,因为它考虑到了浏览器的怪异行为。不过也要注意,宿主对象没有义务保持目前的实现方式不变,也不一定会模仿已有宿主对象的行为。所以,这个函数——以及其他类似函数,都不能百分之百地保证永远可靠。作为开发人员,必须对自己要使用某个功能的风险作出理性的估计。

顶部中部底部