function addCombinator(matcher, combinator, base)

1、源码
复制代码 代码如下:
function addCombinator(matcher, combinator, base) {
 var dir = combinator.dir, checkNonElements = base
   && dir === "parentNode", doneName = done++;

 return combinator.first " " + doneName;

  // We can't set arbitrary data on XML nodes, so they don't
  // benefit from dir caching
  if (xml) {
   while ((elem = elem[dir])) {
    if (elem.nodeType === 1 || checkNonElements) {
     if (matcher(elem, context, xml)) {
      return true;
     }
    }
   }
  } else {
   while ((elem = elem[dir])) {
    if (elem.nodeType === 1 || checkNonElements) {
     outerCache = elem[expando] || (elem[expando] = {});
     if ((cache = outerCache[dir])
       && cache[0] === dirkey) {
      if ((data = cache[1]) === true
        || data === cachedruns) {
       return data === true;
      }
     } else {
      cache = outerCache[dir] = [ dirkey ];
      cache[1] = matcher(elem, context, xml)
        || cachedruns;
      if (cache[1] === true) {
       return true;
      }
     }
    }
   }
  }
 };
}

2、功能

生成关系选择器的执行函数。

3、参数

matcher——位置关系前连续的过滤选择器匹配函数数组,该函数用于匹配通过位置关系获得的节点是否符合选择器要求。在实际执行过程中,该函数可能是关系选择器前已生成的elementMatcher(matchers)。例如:div.map>span,在Sizzle编译遇到>时,会将div.map的编译函数作为第一个参数调用addCombinator函数,用以检查获取的span父节点是否满足div.map这两个条件。

combinator——关系选择器对应Expr.relative中的值,Expr.relative中各种关系选择器的值如下。使用该参数的first属性来确定返回的是仅检查紧邻对象的函数还是遍历所有可能对象的函数。将通过如下代码:elem = elem[dir],获取指定位置关系的节点,其中dir等于combinator.dir。
复制代码 代码如下:
Expr.relative : {
 ">" : {
  dir : "parentNode",
  first : true
 },
 " " : {
  dir : "parentNode"
 },
 "+" : {
  dir : "previousSibling",
  first : true
 },
 "~" : {
  dir : "previousSibling"
 }
}

base——该参数与combinator.dir一起,确定变量checkNonElement的值,代码如下。该值从字面理解为当前检查的是非DOM元素,就是当elem.nodeType!=1的时候,若该值为true,则会执行匹配函数,否则结束本次循环。

4、返回函数

4.1 若关系选择器是>或+,则返回如下函数:
复制代码 代码如下:
function(elem, context, xml) {
 while ((elem = elem[dir])) {
  if (elem.nodeType === 1 || checkNonElements) {
   return matcher(elem, context, xml);
  }
 }
}

4.1.1 功能
若检查element类型节点(即checkNonElements==false),迭代获取elem指定位置关系的第一个element类型节点(elem.nodeType == 1),执行匹配函数,检查该节点是否符合要求,若符合返回true,否则返回false;

若检查所有类型节点(即checkNonElements==true),获取elem指定位置关系的紧邻节点,执行匹配函数,检查该节点是否符合要求,若符合返回true,否则返回false;
有些人或许会问,不是说是紧邻关系吗?那代码中为何要出现迭代获取这一过程呢?这是因为,个别浏览器会把节点文本之间的换行符看成是TextNode,故在处理过程中,需要跳过这些节点,直到下一个element节点。
4.1.2 参数
elem——待检查的单个节点元素。

context——执行整个选择器字符串匹配的上下文节点,大部分时候是没有用途。

xml——当前搜索对象是HTML还是XML文档,若是HTML,则xml参数为false。

4.2  若关系选择器是~或空格,则返回如下函数:
复制代码 代码如下:
//Check against all ancestor/preceding elements
function(elem, context, xml) {
 var data, cache, outerCache, dirkey = dirruns + " " + doneName;

 // We can't set arbitrary data on XML nodes, so they don't
 // benefit from dir caching
 if (xml) {
  while ((elem = elem[dir])) {
   if (elem.nodeType === 1 || checkNonElements) {
    if (matcher(elem, context, xml)) {
     return true;
    }
   }
  }
 } else {
  while ((elem = elem[dir])) {
   if (elem.nodeType === 1 || checkNonElements) {
    outerCache = elem[expando] || (elem[expando] = {});
    if ((cache = outerCache[dir])
      && cache[0] === dirkey) {
     if ((data = cache[1]) === true
       || data === cachedruns) {
      return data === true;
     }
    } else {
     cache = outerCache[dir] = [ dirkey ];
     cache[1] = matcher(elem, context, xml)
       || cachedruns;
     if (cache[1] === true) {
      return true;
     }
    }
   }
  }
 }
};

4.2.1 功能

若检查的是XML文档,则其过程与4.1返回函数一致,见上述代码中if ( XML ) { ... }中大括号内的代码。

若是HTML文档,则根据matcher匹配当前元素,若匹配成功,返回true;否则返回false。

4.2.2 参数
elem——待检查的单个节点元素。

context——执行整个选择器字符串匹配的上下文节点,大部分时候是没有用途。

xml——当前搜索对象是HTML还是XML文档,若是HTML,则xml参数为false。

4.2.3 代码说明

内部变量

dirkey——缓存节点检测结果用的键。在一次执行过程中,若一个节点被检查过,则会在这个节点的dirkey属性(属性名称为dirkey的值)中记录下检测结果(true或false),那么在本次执行过程中,再次遇到该节点时,不需要再次检测了。之所以需要缓存,因为多个节点会存在同一个父节点或兄弟节点,利用缓存可以减少检测的次数,提高性能。

dirruns——每次执行通过matcherFromGroupMatchers组织的预编译代码时都会产生一个伪随机数,用以区别不同的执行过程。
doneName——每次执行addCombinator函数时,done变量都会加1,用以区别生成的不同的位置关系匹配函数。

cachedruns——用来记录本次匹配是第几个DOM元素。例如:div.map>span,有3个元素符合span选择器,则针对每个元素执行>匹配函数时,cachedruns依次为0、1、2。cachedruns的作用按照代码可以直接理解为在一个执行过程中,针对同一个元素使用elementMatchers进行匹配过程中,再次遇到同一个元素时,可以直接从获取不匹配的结果,但是,我想不出哪个情况下会发生这种事情。若有人遇到,请告知,多谢!

代码解释
复制代码 代码如下:
while ((elem = elem[dir])) {
 if (elem.nodeType === 1 || checkNonElements) {
  // 若elem节点的expando属性不存在,则赋予空对象,并同时赋予outerCache
  // 若elem节点的expando属性存在,则将其值赋予outerCache
  outerCache = elem[expando] || (elem[expando] = {});
  /*
   * 若outCache[dir]有值,且其第一个元素等于当前的dirkey,
   *     则说明当前位置选择器在本次执行过程中已检测过该节点,执行if内的语句,从缓存中直接获取结果
   * 若outCache[dir]不存在,或第一个元素不等于当前的dirkey,
   *     则说明当前位置选择器在本次执行过程中还未检测过该节点,执行else内的语句,匹配节点并将结果放入缓存
   */
  if ((cache = outerCache[dir])
    && cache[0] === dirkey) {
   // 若缓存中检测结果等于true或cachedruns的值,则返回检测结果(非true皆为false),
   // 否则继续循环获取上一个符合位置关系的节点进行匹配
   if ((data = cache[1]) === true
     || data === cachedruns) {
    return data === true;
   }
  } else {
   // 将数组[ dirkey ]赋予outerCache[dir]及cache
   cache = outerCache[dir] = [ dirkey ];
   // 将匹配成功,将true赋予cache[1],否则将cachedruns的值赋予cache[1]
   cache[1] = matcher(elem, context, xml)
     || cachedruns;
   // 若匹配结果为true,则返回true,否则继续循环获取上一个符合位置关系的节点进行匹配
   if (cache[1] === true) {
    return true;
   }
  }
 }
}

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。