# 三、遍历

## `find()`与`filter()`方法的区别

`filter()`方法用于过滤包装器集合中包含的当前元素集合。它的使用应该留给需要过滤一组已经选择的元素的任务。例如，下面的代码将过滤包装器集中包含的三个`<p>`元素。

样本:sample36.html

```js
<!DOCTYPE html>
<html lang="en">
<body>
    <p><strong>first</strong></p>
    <p>middle</p>
    <p><strong>last</strong></p>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {  //
Alerts middle, by filtering out the first 
      // and last <p>
elements in the wrapper set. 
      alert($('p').filter(':not(:first):not(:last)').text());
  })(jQuery); </script>
</body>
</html>

```

注意事项:

使用**`filter()`**时，要时刻问自己是否绝对必要。例如， **`$('p').filter(':not(:first):not(:last)')`** 可以在没有 **`filter()`** 的情况下编写，方法是将表达式作为自定义选择器 **`$('p:not(:first):not(:last)')`** 传递给 jQuery 函数。

另一方面，`find()`方法可用于进一步查找当前所选元素的后代。想想`find()`更像是用封装在已经选择的元素中的新元素更新或改变当前包装的集合。例如，下面的代码将使用 **`find()`** 将包裹集从 **`<p>`** 元素更改为两个 **`<strong>`** 元素。

样本:sample37.html

```js
<!DOCTYPE html>
<html lang="en">
<body>
    <p><strong>first</strong></p>
    <p>middle</p>
    <p><strong>last</strong></p>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {
      // Alerts
"strong". 
      alert($('p').find('strong').get(0).nodeName);
  })(jQuery); </script>
</body>
</html>

```

注意事项:

您实际上可以通过使用 **`andSelf()`** 将使用 **`find()`** 方法之前的包装器中的元素与当前元素组合在一起，例如 **`$('p').find('strong').andSelf()`** 。

要带走的概念是`filter()`将只减少(或过滤)包装器集中当前选择的元素，而`find()`实际上可以创建一组全新的包装元素。

注释:

**`find()`****`filter()`**都是可以通过 **`end()`** 撤销的破坏性方法，使用 **`find()`** 或 **`filter()`** 会将包裹好的器械包回复到之前的状态。

## 传递一个函数而不是一个表达式

在您运行并创建用于选择元素的自定义过滤器之前，简单地将遍历`filter()`方法传递给一个函数可能更有意义，该函数允许您检查特定场景的包装器集中的每个元素。

例如，假设您希望用一个当前没有用这个元素包装的`<p>`元素包装一个 HTML 页面中的所有`<img>`元素。

您可以创建一个自定义过滤器来完成此任务，或者您可以使用`filter()`方法，通过向其传递一个函数来确定元素的父元素是否是`<p>`元素，如果不是，则在用`<p>`元素包装集合中剩余的`<img>`元素之前，从集合中移除该元素。

在下面的例子中，我选择了 HTML 页面中的每个`<img>`元素，然后给`filter()`方法传递一个函数，该函数用于迭代包装器集中的每个元素(使用`this`，检查`<img>`元素的父元素是否是 **`<p>`** 元素。

样本:sample38.html

```js
<!DOCTYPE html>
<html lang="en">
<body>
    <img />
    <img />
    <p>
        <img />
    </p>
    <img />
    <p>
        <img />
    </p>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {
      $('img').attr('src', 'http://static.jquery.com/files/rockimg/logo_jquery_215x53.gif').filter(function () { return !$(this).parent('p').length == 1
}).wrap('<p></p>');
  })(jQuery); </script>
</body>
</html>

```

请注意，我正在使用`!`运算符将布尔值从真更改为假。这是因为我想从集合中移除`<p>`元素作为其父元素的`<img>`元素。传递给`filter()`方法的函数只有在函数返回 false 时才会从集合中移除元素。

要点是，如果您正在处理一个孤立的情况，可以通过简单地向 filter 方法传递一个可以进行自定义过滤的函数来避免为单个情况创建自定义过滤器(例如`:findImgWithNoP`)。这个概念相当强大。当我们结合`filter()`方法使用正则表达式测试时，考虑一下什么是可能的。

样本:sample39.html

```js
<!DOCTYPE html>
<html lang="en">
<body>
    <ul>
        <li>jQuery is great.</li>
        <li>It's lightweight.</li>
        <li>It's free!</li>
        <li>jQuery makes
everything simple.</li>
    </ul>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function($){  
      // Wrap a
<strong> element around any text within 
      // a <li> that
contains the pattern "jQuery". 
      var pattern = /jQuery/i;
      $('li').filter(function () { return pattern.test($(this).text());
}).wrap('<strong></strong>');
  })(jQuery); </script>
</body>
</html>

```

## 穿越时空

您可以使用`parent()`、`parents()`和`closest()`方法轻松地遍历 DOM 到祖先元素。了解这些方法之间的差异至关重要。检查下面的代码，确保您理解这些 jQuery 遍历方法之间的区别。

样本:sample40.html

```js
<!DOCTYPE html>
<html lang="en">
<body>
    <div id="parent2">
        <div id="parent1">
            <div id="parent0">
                <div id="start"></div>
            </div>
        </div>
    </div>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script>  (function ($) {
      // Alerts
"parent0" x4 
      alert($('#start').parent().attr('id'));
      alert($('#start').parents('#parent0').attr('id'));
      alert($('#start').parents()[0].id);
      // Gets actual DOM
element 
      alert($('#start').closest('#parent0').attr('id'));
      // Alerts
"parent1" x4 
      alert($('#start').parent().parent().attr('id'));
      alert($('#start').parents('#parent1').attr('id'));
      alert($('#start').parents()[1].id);
      // Gets actual DOM
element. 
      alert($('#start').closest('#parent1').attr('id'));
      // Alerts
"parent2" x4 
      alert($('#start').parent().parent().parent().attr('id'));
      alert($('#start').parents('#parent2').attr('id'));
      alert($('#start').parents()[2].id);
      // Gets actual DOM
element. 
      alert($('#start').closest('#parent2').attr('id'));
  })(jQuery); </script>
</body>
</html>

```

注意事项:

**`closest()`** 和 **`parents()`** 可能看起来具有相同的功能，但 **`closest()`** 实际上会将当前选定的元素包含在其过滤中。

**`closest()`** 一旦找到匹配就停止遍历，而 **`parents()`** 获取所有父节点，然后在可选选择器上进行过滤。因此， **`closest()`** 最多只能返回一个元素。

## 遍历方法接受 CSS 表达式作为可选参数

CSS 表达式不仅传递给 jQuery 函数来选择元素，还可以传递给几个遍历方法。可能很容易忘记这一点，因为许多遍历方法根本不需要使用任何表达式就可以运行，例如`next()`。对于下面的遍历方法，表达式是可选的，但是请记住，您可以选择提供用于过滤的表达式。

*   儿童('表情')
*   下一个(“表达式”)
*   nextAll('表达式')
*   父代('表达式')
*   父母('表达')
*   prev(表达式)
*   preveall _ ' expression ')
*   兄弟姐妹('表达式')
*   最接近('表达式')