JavaScript框架设计
上QQ阅读APP看书,第一时间看更新

6.4 选择器引擎涉及的通用函数

6.4.1 isXML

最强大的前几名选择器引擎都能操作 XML 文档,但 XML 与 HTML 存在很大的差异,没有className,getElementById,并且nodeName是区分大小写,在旧版本IE中还不能直接给XML元素添加自定义属性。因此这区分非常有必要。我们看一下各大引擎的实现吧。

Sizzle的实现如下。

      var isXML = Sizzle.isXML = function( elem ) {
          var documentElement = elem && (elem.ownerDocument || elem).documentElement;
          return documentElement ? documentElement.nodeName !== "HTML" : false;
      };

但这样不严谨,因为XML的根节点可能是HTML标签,比如这样创建一个XML文档:

      try {
          var doc = document.implementation.createDocument(null, 'HTML', null);
          alert(doc.documentElement)
          alert(isXML(doc))
      } catch (e) {
          alert("不支持creatDocument方法")
      }

我们来看mootools的slick的实现。

      var isXML = function(document) {
          return ( !! document.xmlVersion) || ( !! document.xml) || (toString.call(document) ==
      '[object XMLDocument]') || (document.nodeType == 9 && document.documentElement.nodeName !=
      'HTML');
      };

mootools用到了大量属性来进行判定,从mootools1.2到现在还没什么改动,说明还是很可靠的。我们再精简一下。在标准浏览器中,暴露了一个创建HTML文档的构造器HTMLDocument,而IE下的XML元素又拥有selectNodes。

      var isXML = window.HTMLDocument ? function(doc) {
          return !(doc instanceof HTMLDocument)
      } : function(doc) {
          return "selectNodes" in doc
      }

不过这些方法都只是规范,JavaScript 对象可以随意添加,属性法很容易被攻破,最好是使用功能法。无论 XML 或HTML 文档都支持 createElement方法,我们判定创建了元素的nodeName是否区分大小写。

      var isXML = function(doc) {
          return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
      };

这是我当前能给出的最严谨的函数了。