YAOHAIXIAO.COM

HTML(5),CSS(3),JavaScript,DOM,Ajax,JSON,Front-end technologies & Yaohaixiao

热门标签:JavaScript Performance 前端开发 前端性能优化 原创

Rss

Home » Frontend » JavaScript » jQuery » jQuery API » jQuery API 教程 – add() 方法详解

jQuery API 教程 – add() 方法详解

jQuery 官方的 API 文档

Description: Add elements to the set of matched elements.

描述:向匹配的元素集合中添加元素

API 概要

把上面 jQuery 官方的 API 做下总结就是:add() 方法的作用就是向匹配的元素集合中添加元素

add(selector, context) 方法接受两个参数

  • selector: (必选参数)数据类型可以是 String(选择器字符串或者HTML代码片段的字符串)、HTMLElement(单个的DOM节点或者HTMLNodeList)、Object(jQuery 对象) – 要添加的HTML元素。
  • context: [(可选参数)数据类型是HTMLElement(单个的DOM节点)] – 选择器在HTML文档中开始匹配的DOM节点

API 详解

向匹配的元素集合中添加元素,(我的)中文翻译看一来有点绕,没太看懂是吧?不要紧,让我们来看看具体的代码:

<ul class="list" id="list">
	<li>item 1</li>
	<li>item 2</li>
	<li>item 3</li>
	<li>item 4</li>
	<li>item 5</li>
	<li>item 6</li>
	<li>item 7</li>
	<li>item 8</li>
	<li>item 9</li>
	<li>item 10</li>
</ul>	
<p class="post">介绍jquery API 的文章,Cool!</p>
<p class="post">介绍jquery API 的文章,Cool!</p>
<p class="post">介绍jquery API 的文章,Cool!</p>
<p class="post">介绍jquery API 的文章,Cool!</p>
<p class="post post-extra">介绍jquery API 的文章,Cool!</p>
<p class="post post-extra">介绍jquery API 的文章,Cool!</p>

// 这里是为了讲解,实际开发应该这么写:
// var listItems = $('#list > li').add('.post');
var listItems = $('#list > li');
    alert(listItems.length); // -> 10 
    listItems = listItems.add('.post');
    alert(listItems.length); // -> 16

从上面的代码我们可以看到,listItems 默认的赋值是这样的:listItems = $('#list > li')。它的长度值是10,匹配的是是页面中所有 li 标签元素,这些li元素的集合,就是所谓的匹配的元素集合

而接下来listItems = listItems.add('.post') 的作用则是先找到页面中所有的有使用post类选择器的p标签元素(有6个这样的p标签),并将这6个p标签逐个添加到再listItems集合中。看看 listItems.length 的长度值现在变成了16了。这里要注意的关键点是$(‘.post’)匹配的6个p节点是逐个追加到listItems这个(数组)集合中的,而不是将$(‘.post’)这个集合作为整体追加到listItems的。如果是作为整体追加的,listItems的长度值应该为11而不是16。

add() 方法源代码解析

让我们来看看 jQuery 库中 add() 方法的源代码把:

add: function( selector, context ) {
    var set = typeof selector === "string" ?
		jQuery( selector, context ) :
		jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
	    all = jQuery.merge( this.get(), set );

	return this.pushStack( jQuery.unique(all) );
}

将 selector 匹配的 HTML Elements 或者 selector 转变成数组

刚接触 JavaScript 的朋友可能还不清楚这段代码的意思,那我来翻译一下:

var set = typeof selector === "string" ?
    jQuery( selector, context ) :
    jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),

可以写成这样:

var set = null;
// 如果 selector 选择器是字符,
// 例如'p', '.post', '#list > li'这样的 jQuery 可识别的选择器字符
// 或者 '<p>可识别的HTML代码片段</p>'
if(typeof selector === "string"){
    // 一个标准的选择器返回的对象
    // 实例中的 add('.post') 就是执行这个
    // 返回的结果 [p.post,p.post,p.post,p.post,p.post,p.post]
    set = $(selector);
}
else{
    // 如果 selector 是单个HTMLElement的DOM节点
    if(selector && selector.nodeType){
	    // 将这个DOM节点作为一个只有1个值的数组传给 makeArray()方法
		// makeArray 这里不多解释,就是生成一个数组单个值的数组,
		// 这单个值是一个只有个值的数组,看实例会更明白一些
		// $.makeArray([$('#list')]) -> [Object[ul#list.list]]
		// 这单个值也是一个只有一个值的数组,而这个值就是这个DOM节点对象
        set = $.makeArray([ selector ]);
    }
    else{
	    // selector 是一个 HTMLNodeList 或者是 jQuery 对象
		// 也通过makeArray()方法生成数组,你可以试一下 HTMLNodeList
		// $.makeArray(listItems) -> [li, li, li, li, li, li, li, li, li]
		// HTMLNodeList 是一个 ArrayLike 的对象,可以把集合中的每个值保存到到新的数组中
		
		// $.makeArray(Object) -> [Object()]
		// 可以看到,将一个对象 Object 传到makeArray()方法,得到是一个有1个值的数组
        set = $.makeArray(selector);
    }
}

看上面的源代码注释我们可以知道,set 最终的值是一个数组,保存的值就是(本例中) selector 选择器匹配的HTML Elements(6个p节点)。

而当 selector 参数为单个的HTML DOM节点、HTMLNodelist 对象或者jQuery对象的时候,add()方法则调用了makeArray()方法将这些值转换为数组类型的值。

// makeArray() 方法的源代码
// results is for internal usage only
makeArray: function( arr, results ) {
    var ret = results || [];

    if ( arr != null ) {
	    // 当 arr 的数据类型为类似数组类型的值的时候
		// jQuery 中将Array, HTMLNodeList 和还有length属性且有对应数字属性单体对象,arguments对象:
		// var person = {
		//    length:1
		//    "0": 12
		// }
		// var person = {
		//    length:0
		// }
		// 都视作isArraylike
        if ( isArraylike( Object(arr) ) ) {
		    // 将arr和空数组合并
			// merge() 方法在稍后会介绍
            jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr);
        } else {
		    // 当参数 arr 不是类似数组类型的值的时候
		    // makeArray() 方法将 arr 值保存到一个空数组中
			// core_push = [].push()
            core_push.call( ret, arr );
        }
    }

    return ret;
},

本文的重点不是介绍makeArray()方法和如何判断isArraylike,感兴趣的朋友可以自己看下jQuery的源代码。在上面的注释中我给出了makeArray()方法接收不同类型参数会返回的数组的格式。总之,add()方法的第一步是将 selector 匹配的 HTML Elements 或者 selector 转变成数组

使用 merge() 方法合并两个数组(两个匹配的元素集合)

all = jQuery.merge( this.get(), set );

先来看看this.get()中的this指向的是什么?在本例中,this的上下文关系(context)应该是$(‘#list > li’),所以this.get(),也可以这么写:

$('#list > li').get() -> [li, li, li, li, li, li, li, li, li]

this.get()方法则获得是$(‘#list > li’)匹配的HTMLElements的集合的数组,也就是前面一直提起的匹配的元素集合。add()方法接下来会把之前匹配的元素集合也就是this.get()和我们新add()匹配的元素集合(数组)使用merge()方法合并成一个数组。一起来看看下merge()方法是怎么合并两个数组的:

merge: function( first, second ) {
		var l = second.length,
			i = first.length,
			j = 0;

		if ( typeof l === "number" ) {
			for ( ; j < l; j++ ) {
				first[ i++ ] = second[ j ];
			}
		} else {
		    // JavaScript 对象的属性可以是以数字为名的字符串
			// var person = {"0":"robert","1":32};
			while ( second[j] !== undefined ) {
				first[ i++ ] = second[ j++ ];
			}
		}

		first.length = i;

		return first;
	}

second 也就是前面jQuery.merge( this.get(), set )中的set,是一个数组。所以 typeof l === "number"是成立的,merge()方法就会把第二个参数(数组)的值逐个添加到第一个数组中。把jQuery.merge( this.get(), set )换成本例的代码,大致是这样的:

// 输出的结果是使用Firebug 的console.log输出的格式
// all 得到的是一个包含 16 HTMLElement节点数组
jQuery.merge($('#list > li').get(),$('.post')); -> Object[li, li, li, li, li, li, li, li, li, li, p.post, p.post, p.post, p.post, p.post, p.post]

unique() 排序并清除重复值

好了, 最后来看看add()方法最后的返回值的代码吧:

this.pushStack( jQuery.unique(all) );

jQuery.unique(all)是做什么的?仔细看看jQuery中的unique()方法的源代码:

jQuery.unique = Sizzle.uniqueSort;

/**
 * Document sorting and removing duplicates
 * @param {ArrayLike} results
 */
Sizzle.uniqueSort = function( results ) {
	var elem,
		duplicates = [],
		j = 0,
		i = 0;

	// Unless we *know* we can detect duplicates, assume their presence
	hasDuplicate = !support.detectDuplicates;
	sortInput = !support.sortStable && results.slice( 0 );
	results.sort( sortOrder );

	if ( hasDuplicate ) {
	   // 第一次循环:将重复值保存到数组duplicates[]中
		while ( (elem = results[i++]) ) {
			if ( elem === results[ i ] ) {
				j = duplicates.push( i );
			}
		}
		// 第二次循环:将中复制通过splice()方法清除掉
		while ( j-- ) {
			results.splice( duplicates[ j ], 1 );
		}
	}

	return results;
};

注意看看uniqueSort()方法的注释,其实已经说的很清楚了:

/**
 * Document sorting and removing duplicates
 * @param {ArrayLike} results
 */

sorting(排序)removing duplicates(移除重复的值)。uniqueSort()方法大致就是通过JavaScript数组的Array.sort()方法来排序的,然后使用Array.splice()方法移除数组里的值。当然,清除重复值循环遍历了2次才得到最终的结果。

到这里,我们发现了add()方法另外的一个特性:通过add()方法添加的元素值里如果于前面的匹配的元素集合有重复,重复值是不会添加到最终的元素集合中的。

pushStack() 合并生成最终的jQuery(ArrayLink)对象

// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {

		// Build a new jQuery matched element set
		var ret = jQuery.merge( this.constructor(), elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;
		ret.context = this.context;

		// Return the newly-formed element set
		return ret;
	}

我们可以看到,pushStack()方法的关键在merge(this.constructor(), elems)这里的处理,前面也简单介绍过merge()方法,这里要合并是this.constructor()的值和all这个数组。

this.constructor()返回的结果就是一个空的jQuery对象(空数组,不过空jQuery对象不只是一个数组),this.constructor()在本例其实可以写成这样:

$('#list > li').constructor() -> Object[]

Object[],这个显示的形式是通过Firebug的console.log()方法输出的。其实清楚jQuery的人都知道,$()这个方法返回的结果就是一个数组,更准确的说是一个Arraylink的对象。将一个空的jQuery对象和all(另外一个jQuery对象合并)最终得到的了一个新的合并了两个HTMLElements集合的jQuery(数组)对象。到这里所有add()方法的处理就结束了,add()会把合并的结果返回。

结束语

这是我第一次尝试讲解jQuery API,希望我把add()方法分析清楚了,也希望对大家的开发有帮助。其实,在阅读jQuery API和源代码的时候,自己也是一个学习的过程。当然,能力有限,如果有什么说有错误的地方也请大家指正。下次我会接着讲解jQuery API 的addBack()方法,期待哦!

声明:本文采用BY-NC-SA协议进行授权。转载请注明转自:jQuery API 教程 – add() 方法详解

« »

1 条评论

  • 不能只会用,希望能帮助大家真的读懂jQuery

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(Spamcheck Enabled)