发布于:使用 jQuery 核心

jQuery 对象

当创建新元素(或选择现有元素)时,jQuery 会将这些元素作为一个集合返回。许多刚接触 jQuery 的开发者会误以为这个集合是一个数组。毕竟它具有零索引的 DOM 元素序列、一些熟悉的数组函数以及一个 .length 属性。实际上,jQuery 对象比这更复杂。

link DOM 和 DOM 元素

文档对象模型(简称 DOM)是 HTML 文档的一种表示形式。它可以包含任意数量的 DOM 元素。从高层次上看,DOM 元素可以被视为网页的“一块”。它可以包含文本和/或其他 DOM 元素。DOM 元素由类型(例如 <div><a><p>)以及任意数量的属性(例如 srchrefclass 等)来描述。有关更详细的描述,请参阅 W3C 官方 DOM 规范

元素具有属性,就像任何 JavaScript 对象一样。在这些属性中,包括像 .tagName 这样的特性(attributes)和像 .appendChild() 这样的方法。这些属性是唯一通过 JavaScript 与网页进行交互的方式。

link jQuery 对象

事实证明,直接使用 DOM 元素可能会很笨拙。jQuery 对象定义了 许多 方法来为开发者提供更顺畅的体验。jQuery 对象的一些优势包括:

兼容性 – DOM 方法的实现因浏览器厂商和版本而异。以下代码片段尝试设置存储在 target 中的 <tr> 元素的 inner HTML:

1
2
3
var target = document.getElementById( "target" );
target.innerHTML = "<td>Hello <b>World</b>!</td>";

这在许多情况下有效,但在大多数版本的 Internet Explorer 中会失败。在这种情况下,推荐的方法 是使用纯 DOM 方法代替。通过将 target 元素包装在 jQuery 对象中,这些边界情况得到了处理,并在所有支持的浏览器中实现了预期的结果:

1
2
3
4
5
// Setting the inner HTML with jQuery.
var target = document.getElementById( "target" );
$( target ).html( "<td>Hello <b>World</b>!</td>" );

便利性 – 还有许多常见的 DOM 操作用例,使用纯 DOM 方法实现起来很笨拙。例如,要在 target 元素之后插入存储在 newElement 中的元素,需要一个相当冗长的 DOM 方法:

1
2
3
4
5
6
7
// Inserting a new element after another with the native DOM API.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
target.parentNode.insertBefore( newElement, target.nextSibling );

通过将 target 元素包装在 jQuery 对象中,相同的任务变得简单得多:

1
2
3
4
5
6
7
// Inserting a new element after another with jQuery.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
$( target ).after( newElement );

在大多数情况下,这些细节只是阻碍你实现目标的“陷阱”。

link 将元素放入 jQuery 对象中

当使用 CSS 选择器调用 jQuery 函数时,它将返回一个 jQuery 对象,该对象包装了匹配此选择器的所有元素。例如,编写:

1
2
3
// Selecting all <h1> tags.
var headings = $( "h1" );

headings 现在是一个 jQuery 对象,其中包含页面上已有的所有 <h1> 标签。可以通过检查 headings.length 属性来验证这一点:

1
2
3
4
5
// Viewing the number of <h1> tags on the page.
var headings = $( "h1" );
alert( headings.length );

如果页面有多个 <h1> 标签,这个数字将大于一。如果页面没有 <h1> 标签,.length 属性将为零。检查 .length 属性是确保选择器成功匹配一个或多个元素的常用方法。

如果目标是只选择第一个标题元素,则需要额外的步骤。有多种方法可以实现这一点,但最直接的方法是使用 .eq() 函数。

1
2
3
4
5
// Selecting only the first <h1> element on the page (in a jQuery object)
var headings = $( "h1" );
var firstHeading = headings.eq( 0 );

现在 firstHeading 是一个 jQuery 对象,仅包含页面上的第一个 <h1> 元素。由于 firstHeading 是一个 jQuery 对象,它具有像 .html().after() 这样的有用方法。jQuery 还有一个名为 .get() 的方法,它提供了相关功能。它不是返回一个 jQuery 包装的 DOM 元素,而是返回 DOM 元素本身。

1
2
3
// Selecting only the first <h1> element on the page.
var firstHeadingElem = $( "h1" ).get( 0 );

另外,由于 jQuery 对象是“类数组”的,它支持通过方括号进行数组下标访问:

1
2
3
// Selecting only the first <h1> element on the page (alternate approach).
var firstHeadingElem = $( "h1" )[ 0 ];

无论哪种情况,firstHeadingElem 都包含原生的 DOM 元素。这意味着它具有像 .innerHTML 这样的 DOM 属性和像 .appendChild() 这样的方法,但没有.html().after() 这样的 jQuery 方法。firstHeadingElem 元素处理起来更困难,但在某些情况下是必需的。其中一种情况是进行比较。

link 并非所有创建的 jQuery 对象都是 ===

关于这种“包装”行为的一个重要细节是,每个被包装的对象都是唯一的。即使对象是使用相同的选择器创建的或包含对完全相同的 DOM 元素的引用,情况也是如此。

1
2
3
4
// Creating two jQuery objects for the same element.
var logo1 = $( "#logo" );
var logo2 = $( "#logo" );

尽管 logo1logo2 是以相同方式创建的(并包装了相同的 DOM 元素),但它们不是同一个对象。例如:

1
2
3
// Comparing jQuery objects.
alert( $( "#logo" ) === $( "#logo" ) ); // alerts "false"

然而,两个对象都包含相同的 DOM 元素。.get() 方法对于测试两个 jQuery 对象是否具有相同的 DOM 元素很有用。

1
2
3
4
5
6
7
8
9
// Comparing DOM elements.
var logo1 = $( "#logo" );
var logo1Elem = logo1.get( 0 );
var logo2 = $( "#logo" );
var logo2Elem = logo2.get( 0 );
alert( logo1Elem === logo2Elem ); // alerts "true"

许多开发者在包含 jQuery 对象的变量名称前加上 $ 前缀,以帮助区分。这种做法没有什么神奇之处——它只是帮助一些人跟踪不同变量包含的内容。前面的示例可以重写以遵循此约定:

1
2
3
4
5
6
7
8
9
// Comparing DOM elements (with more readable variable names).
var $logo1 = $( "#logo" );
var logo1 = $logo1.get( 0 );
var $logo2 = $( "#logo" );
var logo2 = $logo2.get( 0 );
alert( logo1 === logo2 ); // alerts "true"

此代码的功能与上面的示例相同,但阅读起来更清晰一些。

无论使用何种命名约定,区分 jQuery 对象和原生 DOM 元素都非常重要。原生 DOM 方法和属性在 jQuery 对象上不存在,反之亦然。像“event.target.closest is not a function”和“TypeError: Object [object Object] has no method 'setAttribute'”这样的错误消息表明存在这种常见的错误。

link jQuery 对象不是“实时”的

给定一个包含页面上所有段落元素的 jQuery 对象:

1
2
3
// Selecting all <p> elements on the page.
var allParagraphs = $( "p" );

...人们可能会期望随着 <p> 元素被添加到文档中或从文档中删除,其内容会随时间增加和减少。jQuery 对象以这种方式运行。jQuery 对象中包含的元素集不会改变,除非被明确修改。这意味着集合不是“实时”的——它不会随着文档的更改自动更新。如果自创建 jQuery 对象以来文档可能已更改,则应通过创建新对象来更新集合。这可以像重新运行相同的选择器一样简单:

1
2
3
// Updating the selection.
allParagraphs = $( "p" );

link 总结

尽管 DOM 元素提供了创建交互式网页所需的所有功能,但使用它们可能会很麻烦。jQuery 对象包装这些元素以平滑这种体验并使常见任务变得容易。当使用 jQuery 创建或选择元素时,结果将始终包装在一个新的 jQuery 对象中。如果情况需要原生 DOM 元素,可以通过 .get() 方法和/或数组样式的下标来访问它们。