开发者

jQuery: Why is it that `:first` only returns the first of the result array and not of the selector

开发者 https://www.devze.com 2023-04-08 05:19 出处:网络
http://jsfiddle.net/vol7ron/s5fS8/ HTML: <div class=\"container\"> <span class=\"foo\">a</span>

http://jsfiddle.net/vol7ron/s5fS8/

  • HTML:

    <div class="container">
          <span class="foo">a</span>
          <span class="bar"开发者_C百科>1a</span>
          <span class="bar">2a</span>
    </div>
    <div class="container">
          <span class="foo">b</span>
          <span class="bar">1b</span>
          <span class="bar">2b</span>
    </div>
    <div class="container">
          <span class="foo">c</span>
          <span class="bar">1c</span>
          <span class="bar">2c</span>
    </div>
    
    <div class="title">Debug:</div>
    <pre id="debug"></pre>
    
  • JS:

    var debug      = $('#debug');
    var containers = $('.container');
    var foos       = containers.children('.foo');
    var bars       = foos.siblings('.bar:first');
    
    
    bars.each(function(){
        debug.append($(this).text() + '\n');
    });
    

What happens is the first bar is returned, whereas from an OOP POV, you'd think the first bar from each container would be returned.

As I left in a comment, I'm hung on why :first is applied to the result set, rather than the search set.


I thought the logic was: loop through the array of foos, find all the siblings that are bars, but only return the first one, add it to the array result stack, continue on to the next foo.

Instead, it's: loop through array of foos, find all siblings that are bars, add them to the result stack, select the first one.

I think it should work more like find() where:

  • containers.find('.bar:first') returns the result I'm looking for
  • containers.find('.bar').first(':first') returns the result I'm currently getting (the OOP makes sense)


When you use first you are telling jQuery to get the first it finds from the list you give it not taking into account the parents. To get the result you ask about use this instead:

var bars       = foos.next('.bar');

Demo: http://jsfiddle.net/s5fS8/1/

You can also loop over the containers instead:

var debug      = $('#debug');
var containers = $('.container');

containers.each(function(){
    debug.append($(this).find(".bar:first").text() + '\n');
});


It's just how it's designed:

http://api.jquery.com/first-selector/

By definition, it can only return one element. I wish the functionality was how you described. It is more intuitive to me, but it does not work that way by construction.


Because that's just the way it is. :first is just short-hand for .eq(0) (it's not even really shorter, it's just another way of doing it).

If I've understood what you think :first should be doing, then you should have a look at :first-child.

From the jQuery docs:

The :first pseudo-class is equivalent to :eq(0). It could also be written as :lt(1). While this matches only a single element, :first-child can match more than one: One for each parent.


The definitions took a bit of wrapping my head around when I first read them, but basically:

  • :first returns the first element from a wrapped set, while
  • :first-child returns any element that is the first child in its parent container.

So :first looks at your jQuery object, and :first-child looks at the actual HTML container.

That sounds a bit whacked, but hopefully that made sense. :D

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号