美文网首页JavaScript
《JavaScript高级程序设计》Chapter 9 客户端检

《JavaScript高级程序设计》Chapter 9 客户端检

作者: 云之外 | 来源:发表于2016-09-26 16:13 被阅读120次

    Chapter 9 客户端检测

    能力检测

    1. 用于识别浏览器的能力,基本模式如下

      if (object.propertyInQuestion) {
          // use object.propertyInQuestion
      }
      
      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');
          }
      }
      
    2. 更可靠的能力检测

      • 确定一个对象是否支持排序(既要检测 sort 属性是否存在,也要检测 sort 属性是否是一个函数)
      function isSortable(object) {
          return typeof object.sort == 'function';
      }
      
      • 尽量使用 typeof 进行能力检测。但是在 IE8 之前的版本中,由于宿主对象是通过 COM 而非 JScript 实现的,所以 document.createElement() 之类的函数是一个 COM 对象,而非函数
      typeof document.createElement == 'function' // 在 IE8- 中为 false
      
      • IE 中类似的 typeof 的行为不标准的例子还有很多。
      • 在浏览器环境下测试任何对象的某个属性是否存在,要使用下面这个函数
      function isHostMethod(object, property) {
          var t = typeof object[property];
          return t == 'function' || (!!(t == 'object' && object[property])) || t == 'unknown;
      
      result = isHostMethod(xhr, 'open'); // true
      

      在 JavaScript 中, !! 操作符通常用于将表达式强制转换为 boolean 类型数据。

    3. 能力检测,不是浏览器检测

      • 检测某个或某几个特性并不能够确定浏览器。
      • 如果已知应用程序需要使用某些特定的浏览器特性,最好一次检测所有的相关特性,而不是分别检测。
      // 检测浏览器是否具有 DOM1 级规定的能力。
      var hasDOM1 = !! (document.getElementById && document.createElement && document.getElementByTagName);
      

    怪癖检测

    1. 怪癖检测的目标是识别浏览器的特殊行为。通过怪癖检测,获知浏览器存在什么样的缺陷。

    2. Example: IE8- 中,如果某个实例属性与 [[Enumerable]] 标记为 false 的某个原型属性同名,那么该实例属性将不会出现在 for-in 循环当中。

      var hasDontEnumQuirk = function() {
          var o = {toString: function() {
              for(var prop in o) {
                  if(prop == 'toString') {
                      return false;
                  }
              }
          }
          return true;
      }();
      
    3. Example: Safari3- 中,会枚举被隐藏的属性。

    var hasEnumShadowsQuirk() {
        var o = {toString: function() {
            var count = 0;
            for (var prop in o) {
                if (prop == 'toString') {
                    count++;
                }
            }
            return (count > 1);
        }();
    
    3. Example: Safari3- 中,会枚举被隐藏的属性。
    
    ```
    var hasEnumShadowsQuirk() {
        var o = {toString: function() {
            var count = 0;
            for (var prop in o) {
                if (prop == 'toString') {
                    count++;
                }
            }
            return (count > 1);
        }();
    ```
    

    用户代理检测

    1. 用户代理检测通过检测用户代理字符串来确定实际使用的浏览器。在每一次 HTTP 请求过程中,用户代理字符串是作为相应首部发送的,而且该字符串可以通过 JavaScript 的 navigator.userAgent 属性访问。

      • 在服务器端,用户代理检测被广泛使用。
      • 在客户端,用户代理检测的优先级排在能力检测 / 怪癖检测之后。
    2. 电子欺骗:浏览器通过在自己的用户代理字符串加入一些错误或误导信息,来达到欺骗服务器的目的。

    3. 用户代理字符串

      • RFC2616 规定格式:标识符/产品版本号
      • IE4 ~ IE7:Mozilla/4.0 (平台; MSIE 版本号; 操作系统)
      • IE8:Mozilla/4.0 (compatible; MSIE 版本号; Trident/Trident 版本号)
        • Trident 记号是为了让开发人员知道 IE8 是不是在兼容模式下运行,如果是,则 MSIE 版本号会变成 7。
      • IE9:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
      • IE9 兼容模式:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0)
      • Gecko:Mozilla/Mozilla 版本号 (平台; 加密类型; 操作系统或CPU; 语言; 预先发型版本) Gecko/Gecko 版本号 应用程序或产品/引用程序或产品版本号
        • 具体查手册
      • Firefox4: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox 4.0.1
      • Webkit:Mozilla/5.0 (平台; 加密类型; 操作系统或CPU; 语言) AppleWebkit/AppleWebkit 版本号 (KHTML, like Gecko) Safari/Safari 版本号
        • 基于 Webkit 的所有浏览器都将自己标识为 Mozilla 5.0
      • Safari3:Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebkit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5
      • Konqueror 略
      • Chrome7:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebkit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7
      • Opera8:Opera/版本号 (操作系统或CPU; 加密类型; 语言)
      • Opera9:Mozilla/5.0 (Windows NT 5.1; U; en-US; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50
        • Opera隐藏了自己的身份,伪装成 Firefox 或 IE,无法将 Opera 与其他浏览器区别开来。
      • Opera10:Opera/9.80 (操作系统或CPU; 加密类型; 语言) Presto/Presto 版本号 Version/版本号
      • iOS 和 Android:同桌面版
    4. 用户代理字符串检测技术

      • 识别呈现引擎

        • 检测五大引擎:IE、Gecko、WebKit、KHTML、Opera
        • 使用模块增强模式封装检测脚本
        var client = function() {
            var engine = {
                ie: 0,
                gecko: 0,
                webkit: 0,
                khtml: 0,
                opera: 0,
                
                ver: null
            };
            
            return {
                engine: engine
            };
        }();
        
        • 如果检测到了哪个呈现引擎,就以浮点数值形式将该引擎的版本号写入相应的属性。而呈现引擎的完整版本(是一个字符串),则被写入 ver 属性。
        if(client.engine.ie) {
            // 针对 IE 的代码
        } else if (client.engine.gecko > 1.5) {
            if (client.engine.ver == '1.8.1') {
                // 针对这个版本执行某些代码
            }
        }
        
        • 识别 Opera 必须检测 window.opera 对象。
        if (window.opera) {
            engine.var = window.opera.version();
            engine.opera = parseFloat(engine.ver);
        
        • 识别 WebKit 和 KHTML 见手册。
      • 识别浏览器(具体见文档)

      var browser = {
          ie: 0,
          firefox: 0,
          safari: 0,
          konq: 0,
          opera: 0,
          chrome: 0,
          ver: null
      };
      
      • 识别平台(具体见文档)
      var system = {
          win: false,
          mac: false,
          x11: false
      };
      var p = navigator.platform;
      system.win = p.indexOf('Win') == 0;
      system.mac = p.indexOf('Mac') == 0;
      system.x11 = (p.indexOf('X11') == 0) || (p.indexOf('Linux') == 0); 
      
      • 识别移动设备(具体见文档)
      var system = {
          win: false,
          mac: false,
          x11: false,
          
          iphone: false,
          ipod: false,
          ipad: false,
          ios: false,
          android: false,
          nokiaN: false,
          winMobile: false
      };
      var p = navigator.platform;
      system.win = p.indexOf('Win') == 0;
      system.mac = p.indexOf('Mac') == 0;
      system.x11 = (p.indexOf('X11') == 0) || (p.indexOf('Linux') == 0); 
      
      system.iphone = ua.indexOf('iPhone') > -1;
      system.ipod = ua.indexOf('iPod') > -1;
      system.ipad = ua.indexOf('iPad') > -1;
      system.nokiaN = ua.indexOf('NokiaN') > -1;
      system.winMobile = (system.win == 'CE');
      
      • 识别游戏系统(略)
    5. 完整的代码(看文档)

    相关文章

      网友评论

        本文标题:《JavaScript高级程序设计》Chapter 9 客户端检

        本文链接:https://www.haomeiwen.com/subject/jguqyttx.html