资讯专栏INFORMATION COLUMN

JavaScript 客户端检测(高程三)

msup / 987人阅读

摘要:客户端检测方式能力检测怪癖检测用户代理检测能力检测最常用也是最为人们广泛接受的客户端检测形式是能力检测又称特性检测。在可能的情况下,尽量使用进行能力检测。

客户端检测方式

能力检测

怪癖检测

用户代理检测

能力检测

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

 if(object.propertyInQuestion){
     // 使用object.propertyInQuestion
 }

要理解能力检测,首先必须理解两个重要的概念。

先检测达成目的的最常用的特性

必须测试实际要用到的特性,一个特性存在,不一定意味着另一个特性也存在

更可靠的能力检测
通过 typeof 确定是否为函数,进行能力检测。

 // 检查sort是不是函数
 function isSortable(object){
     return typeof object.sort == "function";
 }

typeof 操作符用于确定 sort 的却是函数,因此可以调用他对数据进行排序。
在可能的情况下,尽量使用 typeof 进行能力检测。特别是宿主对象没有义务让 typeof 返回合理值。

能力检测,不是浏览器检测
检测某个或某几个特性并不能够确定浏览器。实际上,根据浏览器不同将能力组合起来是更可取的方式,最好是一次性检测所有相关特性,而不要分别检测。

// 确定浏览器是否支持Netspace风格的插件
var hasNSPlugins = !!(navigator.plugins && navigator.pligins.length);
// 确定浏览器是否具有DOM1级别规定的能力
var hasDOM1 = !!(document.getElementById && document.createElement && document.getElementByTagName);

得到的布尔值可以在后继续使用,从而节省重新检测能力的时间。

怪癖检测

与能力检测类似,怪癖检测的目标是识别浏览器的特殊行为。但与能力检测确认浏览器支持什么能力不同,怪癖检测是想要知道浏览器存在什么缺陷("怪癖" 也就是 bug)。这通常需要运行一小段代码,以确定某一特性不能正常工作。

例如,IE8及更早版本中存在一个bug,即如果某个实例属性与[[Enumerable]]标记为 false 的某个原型属性同名,那么该实例属性将不会出现在 for-in 循环当中。

  var hasDontEnumQuik = function(){
      var o = {toString : function(){}};
      for(var props in o){
          if (props == "toString"){ 
              return false ;  
          }
      }
      return true;
  }();

一般来说,“怪癖”都是个别浏览器所独有的,而且通常被归为 bug。在相关浏览器的新版本中,这些问题可能会也可能不会被修复。由于检测 “怪癖” 设计运行代码,因此我们建议仅检测那些对你有直接影响的 “怪癖”,而且最好在脚本一开始就执行此类检测,以便尽早解决问题。

用户代理检测

用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。在每一次 HTTP 请求过程中,用户代理字符串是作为响应首部发送的,而且该字符串可以通过 JavaScript 的 navigator.userAgent 属性访问。在服务器端,通过检测用户代理字符串来确定用户使用的浏览器是一种常用而且广为接受的做法。而在客户端,用户代理检测一般被当做一种万不得已才用的做法,其优先级排在能力检测和(或)怪癖检测之后。

以下是完整的用户代理字符串检测脚本,包括检测呈现引擎、平台、window操作系统、移动设备和游戏系统。

    var client = function(){

        // rendering engines
        var engine = {            
            ie: 0,
            gecko: 0,
            webkit: 0,
            khtml: 0,
            opera: 0,

            // complete version
            ver: null  
        };
        
        // browsers
        var browser = {
            
            // browsers
            ie: 0,
            firefox: 0,
            safari: 0,
            konq: 0,
            opera: 0,
            chrome: 0,

            // specific version
            ver: null
        };

        // platform/device/OS
        var system = {
            win: false,
            mac: false,
            x11: false,
            
            // mobile devices
            iphone: false,
            ipod: false,
            ipad: false,
            ios: false,
            android: false,
            nokiaN: false,
            winMobile: false,
            
            // game systems
            wii: false,
            ps: false 
        };    

        // detect rendering engines/browsers
        var ua = navigator.userAgent;    
        if (window.opera){
            engine.ver = browser.ver = window.opera.version();
            engine.opera = browser.opera = parseFloat(engine.ver);
        } else if (/AppleWebKit/(S+)/.test(ua)){
            engine.ver = RegExp["$1"];
            engine.webkit = parseFloat(engine.ver);
            
            // figure out if it"s Chrome or Safari
            if (/Chrome/(S+)/.test(ua)){
                browser.ver = RegExp["$1"];
                browser.chrome = parseFloat(browser.ver);
            } else if (/Version/(S+)/.test(ua)){
                browser.ver = RegExp["$1"];
                browser.safari = parseFloat(browser.ver);
            } else {
                // approximate version
                var safariVersion = 1;
                if (engine.webkit < 100){
                    safariVersion = 1;
                } else if (engine.webkit < 312){
                    safariVersion = 1.2;
                } else if (engine.webkit < 412){
                    safariVersion = 1.3;
                } else {
                    safariVersion = 2;
                }   
                
                browser.safari = browser.ver = safariVersion;        
            }
        } else if (/KHTML/(S+)/.test(ua) || /Konqueror/([^;]+)/.test(ua)){
            engine.ver = browser.ver = RegExp["$1"];
            engine.khtml = browser.konq = parseFloat(engine.ver);
        } else if (/rv:([^)]+)) Gecko/d{8}/.test(ua)){    
            engine.ver = RegExp["$1"];
            engine.gecko = parseFloat(engine.ver);
            
            // determine if it"s Firefox
            if (/Firefox/(S+)/.test(ua)){
                browser.ver = RegExp["$1"];
                browser.firefox = parseFloat(browser.ver);
            }
        } else if (/MSIE ([^;]+)/.test(ua)){    
            engine.ver = browser.ver = RegExp["$1"];
            engine.ie = browser.ie = parseFloat(engine.ver);
        }
        
        // detect browsers
        browser.ie = engine.ie;
        browser.opera = engine.opera;
        
        // detect platform
        var p = navigator.platform;
        system.win = p.indexOf("Win") == 0;
        system.mac = p.indexOf("Mac") == 0;
        system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);

        // detect windows operating systems
        if (system.win){
            if (/Win(?:dows )?([^do]{2})s?(d+.d+)?/.test(ua)){
                if (RegExp["$1"] == "NT"){
                    switch(RegExp["$2"]){
                        case "5.0":
                            system.win = "2000";
                            break;
                        case "5.1":
                            system.win = "XP";
                            break;
                        case "6.0":
                            system.win = "Vista";
                            break;
                        case "6.1":
                            system.win = "7";
                            break;
                        default:
                            system.win = "NT";
                            break;                
                    }                            
                } else if (RegExp["$1"] == "9x"){
                    system.win = "ME";
                } else {
                    system.win = RegExp["$1"];
                }
            }
        }
        
        // mobile devices
        system.iphone = ua.indexOf("iPhone") > -1;
        system.ipod = ua.indexOf("iPod") > -1;
        system.ipad = ua.indexOf("iPad") > -1;
        system.nokiaN = ua.indexOf("NokiaN") > -1;
        
        // windows mobile
        if (system.win == "CE"){
            system.winMobile = system.win;
        } else if (system.win == "Ph"){
            if(/Windows Phone OS (d+.d+)/.test(ua)){;
                system.win = "Phone";
                system.winMobile = parseFloat(RegExp["$1"]);
            }
        }
        
        // determine iOS version
        if (system.mac && ua.indexOf("Mobile") > -1){
            if (/CPU (?:iPhone )?OS (d+_d+)/.test(ua)){
                system.ios = parseFloat(RegExp.$1.replace("_", "."));
            } else {
                system.ios = 2;  // can"t really detect - so guess
            }
        }
        
        // determine Android version
        if (/Android (d+.d+)/.test(ua)){
            system.android = parseFloat(RegExp.$1);
        }
        
        // gaming systems
        system.wii = ua.indexOf("Wii") > -1;
        system.ps = /playstation/i.test(ua);
        
        // return it
        return {
            engine:     engine,
            browser:    browser,
            system:     system        
        };
    }();

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103093.html

相关文章

  • javascript高程3 学习笔记()

    摘要:与执行环境相关的变量对象中有执行环境定义的所有变量和函数作用域链代码在一个环境中执行,便会创建变量对象的一个作用域链。 执行环境 执行环境是什么? javascript的解释器每次开始执行一个函数时,都会为每个函数创建一个执行环境(execution context)。 执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为。 与执行环境相关的变量对象(...

    avwu 评论0 收藏0
  • JavaScript高程----(基础一)

    摘要:大小写的不同分别表示不同的变量。本质由一组无序的名值对组成的。字符串中第一个小数点有效,第二个无效,后面的字符串会被忽略。注意双引号开头,必须以双引号结尾,单引号也是如此转义字符表示非打印字符或具有其他用途的字符。 JavaScript高级程序设计(第3版)读书笔记 1.区分大小写: 变量、函数名和操作符都要区分大小写。大小写的不同分别表示不同的变量。 2.标识符: 变量、函数、属性...

    cppowboy 评论0 收藏0
  • 高程3总结#第8章BOM

    摘要:对象的核心对象是,它表示浏览器的一个实例。而和则表示该容器中页面视图区的大小。在中,与返回相同的值,即视口大小而非浏览器窗口大小。第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。这应该是用户打开窗口后的第一个页面 BOM window对象 BOM的核心对象是window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访...

    MASAILA 评论0 收藏0
  • 错误检测(1)------try-catch语句 From 《高程3》

    摘要:类型的错误会在数值超出相应范围时触发。最常发生类型错误的情况,就是传递给函数的参数事先未经检查,结果传入类型与预期类型不相符。捕获错误的目的在于避免浏览器以默认方式处理它们而抛出错误的目的在于提供错误发生具体原因的消息。 0 前言 目前读到了《高程3》的错误检测部分,现在先挖一个坑,关于错误检测应该写三篇总结:firebug检测错误和输出信息;try-catch错误捕获;常见错误种类。...

    UnixAgain 评论0 收藏0
  • 错误检测(1)------try-catch语句 From 《高程3》

    摘要:类型的错误会在数值超出相应范围时触发。最常发生类型错误的情况,就是传递给函数的参数事先未经检查,结果传入类型与预期类型不相符。捕获错误的目的在于避免浏览器以默认方式处理它们而抛出错误的目的在于提供错误发生具体原因的消息。 0 前言 目前读到了《高程3》的错误检测部分,现在先挖一个坑,关于错误检测应该写三篇总结:firebug检测错误和输出信息;try-catch错误捕获;常见错误种类。...

    Thanatos 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<