文章目录
  1. 1. 主要功能分支:
  2. 2. jQuery选择器支持9种方式的处理
  3. 3. 正则解析
  4. 4. match的取值
  5. 5. 匹配模式一:html代码\
    1. 5.1. 参数selector是HTML代码的处理
  6. 6. 匹配模式二:$(“#id”),context未传入
    1. 6.1. 参数selector是#id,context未传入时的处理
  7. 7. 匹配模式三:$(selector),selector选择器表达式
  8. 8. 匹配模式四:$(selector,context)context是jQuery对象
  9. 9. 匹配模式五:$(selector,context)context不是jQuery对象
  10. 10. 匹配模式六:$(jQuery对象)
  11. 11. 匹配模式七:$(fn)

主要功能分支:

  • selector可以转换为false,如””,null,undefined,false,返回this 示例:$(undefined)
  • selector为字符串 示例:$("<div></div>)或$("#id")或$("div")
  • selector为DOM元素,手动设置第一个元素和属性context指向该DOM元素,属性length为1,然后返回包含该DOM元素引用的jQuery对象 示例:$(document)
  • selector是函数,则认为是绑定ready事件,示例:$(function(){})
  • selector是jQuery对象,参数selector包含属性selector,则认为它是jQuery对象,将会复制它的属性selector和context 示例:$($('div p'))

jQuery选择器支持9种方式的处理

API:

  • jQuery( selector[,context] ); $(“.test”,$(“body”));
  • jQuery( element ) 示例:$(document);
  • jQuery( elementArray ) 示例:$(myForm.elements);
  • jQuery( object ) 示例:$({foo:”bar”,hello:”hello”});
  • jQuery( jQuery object ) 示例:$($(‘.test’));
  • jQuery(); 示例:$();$(false);
  • jQuery( html[,ownerDocument] ) 示例:$(“\
    “,document);
  • jQuery( html,attributes ) 示例:$(“\“,{“src”:”a.png”});
  • jQuery( callback ) 示例:$(function(){});

代码组织结构:

1
init : function(selector, context, rootjQuery){
	var match,elem;
	// HANDLE: $(""), $(null), $(undefined), $(false)
	if(!selector){
		return this;
	}
	// Handle HTML strings
	if(typeof selector === 'string'){
	// HANDLE: $(DOMElement)
	}else if(selector.nodeType){
		this.context = this[0] = selector;
		this.length = 1;
		return this;
	// HANDLE: $(function)
	// Shortcut for document ready
	}else if(jQuery.isFunction(selector)){
		return rootjQuery.ready(selector);
	}
	if(selector.selector !== undefined){
		this.selector = selector.selector;
		this.context  = selector.context;
	}
	return jQuery.makeArray(selector,this);
}

正则解析

rquickExpr

1
var rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;

  1. (?:pattern):匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“or”字符 (|) 组合模式部件的情况很有用。例如,’industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。
  2. 选择二义 : 匹配\s*(<[\w\W]+>)[^>]*开头或#([\w-]*)结尾
  3. \s*(<[\w\W]+>)[^>]*:
    • \s*:匹配任何空白字符,包括空格、制表符、换页符等等零次或多次,等价于{0,}
    • (pattern):匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,使用 $0…$9 属性
    • [\w\W]+:匹配于’[A-Za-z0-9]’或[^A-Za-z0-9]’ 一次或多次,等价{1,}
    • (<[wW]+>) :这个表示字符串里要包含用\<>包含的字符,例如\,\等等都是符合要求的
    • [^>]* : 负值字符集合,字符串尾部是除了>的任意字符或者没有字符,零次或多次等价于{0,}
  4. #([\w-]*):匹配结尾带上#号的任意字符,包括下划线与-
  5. exec方法介绍:如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。
    • 此数组的第 0 个元素是与正则表达式相匹配的文本
      • 第1个元素是与RegExpObject的第1个子表达式相匹配的文本(如果有的话)
      • 第2个元素是与RegExpObject的第2个子表达式相匹配的文本(如果有的话),以此类推

正则测试:

1
2
3
4
5
6
var rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;
console.log(rquickExpr.exec("#id"));//["#id",undefined,"id"];
console.log(rquickExpr.exec("<div>"));//["<div>","<div>",undefined];
console.log(rquickExpr.exec(" <div>"));//[" <div>","<div>",undefined];
console.log(rquickExpr.exec(" <div>abc#id"));
console.log(rquickExpr.exec("#id<div>"));//null

rsingleTag

1
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;

  1. ^<(\w+)\s*\/?>:以<开头,跟一个或多个字符和任意个空白字符,接着判断/出现0次或1次,从而判断是否自关闭或不关闭,(\w+)该分组中不包含左右尖括号,不能包含属性。
  2. (?:<\/\1>|)$:\1指向匹配的第一个分组(\w+)

正则测试:

1
2
3
4
5
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
rsingleTag.exec("<div>");//["<div>", "div"]
rsingleTag.exec("<div>abc");//null
rsingleTag.exec("<img/>");//["<img/>", "img"]
rsingleTag.exec("<img name/>");//null

match的取值

1
2
3
4
5
6
7
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];

} else {
match = rquickExpr.exec( selector );
}

selector如果以<开头,以>结尾,并且selector.length大于3就假设这个字符串是HTML片段。否则,用正则rquickExpr.exec检测较为复杂的HTML代码或#id。相关结果都存储在match中。

  • match[0]:表示输入的selector
  • match[1]:表示匹配的HTML代码或undefined
  • match[2]:表示匹配的Id或undefined

匹配模式一:html代码\

参数selector是HTML代码,或者是#id,并且未传入参数context

1
if( match && (match[1] || !context) ){}

参数selector是HTML代码的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if(match[1]){
context && context instanceof jQuery ? context[0] : context;

jQuery.merge(this,jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
));
// 示例:$("<div>",{"prop":"name"});
if(rsingleTag.test(match[1]) && jQuery.isPlainObject(context)){
for(match in context){
if(jQuery.isFunction(this[match])){
this[match](context[match]);
}else{
this.attr(match,context[match]);
}
}
}
return this;
// HANDLE: $(#id)
}else{}

一. 当传入context时,判断context是否为jQuery对象,如果是直接取context[0],直接取context的html元素。

1
context && context instanceof jQuery ? context[0] : context;

二. ownerDocument与documentElement区别

1
context && context.nodeType ? context.ownerDocument || context : document

  • node.ownerDocument是Node对象的属性,返回当前节点所在文档的文档节点,即document对象
  • document.documentElement是Document对象属性,返回文档对象(document)的根元素(例如:HTML文档的元素)

三. 调用jQuery.merge()和jQuery.parseHTML(),进行创建新元素或创建代码片断的处理

  • jQuery.merge(first,second)合并两个数组内容到第一个数组。
  • jQuery.parseHTML(data[,context][,keepScripts])将字符串转换为一组DOM元素。

jQuery.parseHTML

1
2
var str = "Hello,<b>my name is</b> jQuery.";
$.parseHTML(str);//["Hello,",<b>my name is</b>," jQuery."]

jQuery.parseHTML的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
parseHTML:function(data,context,keepScripts){
if(!data || typeof data !== "string"){
return null;
}
if(typeof context === "boolean"){
keepScripts = context;
context = false;
}
context = context || document;
var parsed = rsingleTag.exec(data),
scritps = !keepScripts || [];
if(parsed){
return [context.createElement(parsed[1])];
}
parsed = jQuery.buildFragment([data],context,scritps);
if(scritps){
jQuery(scritps).remove();
}
return jQuery.merge([],parsed.childNodes);
}

  • var parsed = rsingleTag.exec(data);通过正则判断传入的data是否为单独标签,如果是则调用createElement创建标签对应的DOM元素,并且把创建的DOM元素放入数组中,是为了在后面方便的调用jQuery.merge()方法。
  • parsed = jQuery.buildFragment([data],context,scripts);如果data是个复杂的html代码,则利用浏览器的innerHTML机制创建DOM元素。

四. 当HTML代码是单独标签,且第二参数context为一个非空纯对象

1
2
3
4
5
6
7
8
9
if(rsingleTag.test(match[1]) && jQuery.isPlainObject(context)){
for(match in context){
if(jQuery.isFunction(this[match])){
this[match](context[match]);
}else{
this.attr(match,context[match]);
}
}
}

jQuery.isPlainObject()判断当前传入的内容是否是纯粹对象(通过”{}”或new Object创建)

示例:

1
2
3
$("<div></div>");
$("<img/>");
$("<div></div>",{"test","test"});

通过for读取context属性,如果当前jQuery对象也有这个属性并且属性为function,则调用该jQuery对象的这个属性,传入的参数为context中该属性的值;如果该属性不为function,则调用attr,把context的当前属性和值添加到当前jQuery对象上。

1
2
3
var jqHTML = $("<div></div>",{class:'css-class',data-name:'data-val'});
jqHTML.attr['class'];//css-class
jqHTML.attr['data-nae'];//data-val

匹配模式二:$(“#id”),context未传入

参数selector是#id,context未传入时的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
if ( match && (match[1] || !context) ) {

// HANDLE: $(html) -> $(array)
if ( match[1] ) {
...

// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );

// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}

// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}

this.context = document;
this.selector = selector;
return this;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
elem = document.getElementById( match[2] );

// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}

// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}

this.context = document;
this.selector = selector;
return this;

一. 调用document.getElementById()查找含有指定id属性的DOM元素。

1
elem = document.getElementById(match[2]);

二. 检查parentNode属性,因为Blackberry4.6会返回已经不在文档中的DOM节点

1
elem && elem.parentNode

如果所找到的元素的id与传入的值不等,则调用Sizzle查找并返回一个含有选中元素的新jQuery对象。即使是document.getElementById()这样核心的方法也需要考虑浏览器的兼容问题,在IE6,IE7,某些版本的Opera中,可能会按属性name查找而不是id.

如下面的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta name="description" content="head meta description">
</head>
<body>
<div id="description">
body div description
</div>
<form name="divId">
<div id="divId"></div>
</form>
<script>
alert(document.getElmentById("desc").outerHTML);
//IE7返回:<meta name="description" content="head meta description">
alert(document.getElmentById("divId").outerHTML);
//IE7返回:<form name="divId"><div id="divId"></div></form>
</script>

</body>
</html>

三. 如果所找到的元素的属性id值与传入的值相等,则设置第一个元素,属性length,selector,context,并返回当前jQuery对象。

1
2
3
4
5
this.length = 1;
this[0] = elem;

this.context = document;
this.selector = selector;

匹配模式三:$(selector),selector选择器表达式

如果第一个元素是一个选择器,如.className,且未指定上下文

1
return rootjQuery.find(selector);

匹配模式四:$(selector,context)context是jQuery对象

如果第一个元素是一个选择器,如.className,指定上下文是jQuery对象

1
return context.find(selector);

两种模式结合统一这样处理:

1
return (context || rootjQuery).find(selector);

匹配模式五:$(selector,context)context不是jQuery对象

如果第一个元素是一个选择器,如.className,指定上下文是不是jQuery对象,则执行

1
this.constructor(context).find(selector);

先创建一个包含了context的jQuery对象,然后在该jQuery对象上调用方法.find()

匹配模式六:$(jQuery对象)

如果参数selector含有属性selector,则认为它是jQuery对象,将会复制它的属性selector和context。

1
2
3
4
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}

匹配模式七:$(fn)

如果参数selector是函数,则认为是绑定ready事件。

1
return rootjQuery.ready(selector);

文章目录
  1. 1. 主要功能分支:
  2. 2. jQuery选择器支持9种方式的处理
  3. 3. 正则解析
  4. 4. match的取值
  5. 5. 匹配模式一:html代码\
    1. 5.1. 参数selector是HTML代码的处理
  6. 6. 匹配模式二:$(“#id”),context未传入
    1. 6.1. 参数selector是#id,context未传入时的处理
  7. 7. 匹配模式三:$(selector),selector选择器表达式
  8. 8. 匹配模式四:$(selector,context)context是jQuery对象
  9. 9. 匹配模式五:$(selector,context)context不是jQuery对象
  10. 10. 匹配模式六:$(jQuery对象)
  11. 11. 匹配模式七:$(fn)