jQuery构造函数init参数分析续

   其实楼主的F和jQuery.fn.init是相等的; 实现功能是和jq一样的, 只是jq的把构造函数放进原型;如果非要说原因,个人理解jq这样写整体结构清晰,先是入口构造函数,紧跟着是原型部分(原型里面init是初始化),但是不好理解;乍一看确实挺绕, 我也是看了好久才明白怎么回事

  如果selector是其他字符串情况就比较多了比较复杂了

  ?

1
2

// Handle HTML strings
if ( typeof selector === "string" ) {...}

  开始分不同的情况处理

  ?

1
2
3
4
5
6
7

// Are we dealing with HTML string or an ID?
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 = quickExpr.exec( selector );
}

  If里面先判断第一个字符是“<”最后一个字符是“>”并且长度大于3就假设此时的selector是html简单标签 ,比如$(‘

')但是记住仅仅是假设”assume”比如$(‘')这样的也会走这里。然后把match数组修改成[null,selector,null],这里的match是在init函数里面声明的变量,主要是用来作为区分是参数类型的工具稍后在将可能情况列出,下面是源码中声明的四个变量

 

  ?

1
2

init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;

  如果不满足if的条件就会调用一个正则去得到match的结果,quickExpr是jQuery构造函数里面声明的变量

  ?

1
2
3

// A simple way to check for HTML strings or ID strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
quickExpr = /^(?:[^#<]*(<[wW]+>)[^>]*$|#([w-]*)$)/,

  这个正则主要是为了区别html字符串和id字符串的,第二个注释中讲到了为了避免基于 location.hash的 XSS 攻击,于是在 quickExpr 中增加了 #(#9521)的意思是我们可以在jQuery官网找到相关解释。

  首先访问http://bugs.jquery.com/然后搜索对应的值即可

  quickExpr.exec( selector )执行的结果可以是一个数组,数组的第一个元素是匹配的元素,剩下的分别是分组匹配的元素,这个正则有两个分组(<[wW]+>)[^>]和([w-]*)一个是标签一个是id值。最终会把结果交给match。下面就来分析下match的各种情况首先单标签不用正则式是 [ null, selector, null ]的形式,下面在代码中证明:

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13

<!doctype html>
<html>
<head>
<title></title>
<script src='jquery-1.7.1.js'></script>
</head>
<body>
<div id='div'></div>
</body>
<script>
$('<div>');
</script>
</html>

  在html里面我们创建一个jQuery对象然后再init方法里面输出得到的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 = quickExpr.exec( selector );
}
console.log(match); // [null, "<div>", null];

  下面我们修改一下参数改为$(‘#div')然后再看一下结果

   代码如下:

  ["#div", undefined, "div", index: 0, input: "#div"]

  还有一种比较特殊的情况$(‘

123')然后我们再看一下结果

 

  代码如下:

  ["

dewrwe", "
", undefined, index: 0, input: "
dewrwe"]

 

  我们可以看到id总是在第三个元素而标签值在第二个元素保存着,对于最后一种情况而言跟$(‘

')是没有什么区别的因为生成dom元素时是不会处理第一个元素的。基于这个结果可以接着来分析下一个判断了。

 

  接下来的会根据match的结果分为三种情况

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13

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

  第一种情况满足的条件是match一定要有值,match[1]就是第二个元素就是保存标签的这个有值或者不存在上下文,但是好像没有id什么事啊?其实不是的通过分析match的结果可以知道第二个元素没有值肯定就是id选择器得到的结果,而id是唯一的,不需要写上下文(其实写了上下文也会正常执行只不过会使用Sizzle而不是在这里处理了跟body是一样的)。好了第一个条件进来的情况就是

  1.标签

  $(‘

') $(‘
123') $(‘
23213213
')...

 

  2.没有上下文的id $(‘#div')

  第一个条件内部又进行了细分:

  ?

1
2
3
4
5
6
7
8
9
10

// HANDLE: $(html) -> $(array)
if ( match[1] ) {
 
...
 
// HANDLE: $("#id")
 
}else{
 
}

  很显然if是处理标签的else是处理id的,先来看看是怎么处理标签的吧

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

context = context instanceof jQuery ? context[0] : context;
doc = ( context ? context.ownerDocument || context : document );
 
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );
 
if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
 
} else {
selector = [ doc.createElement( ret[1] ) ];
}
 
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}
 
return jQuery.merge( this, selector);

  首先修正一下context的值,如果是jQuery对象就把他变成dom元素就是使用下标的方法这个原理之前说过了,然后有处理了doc变量,如果context不存在就把document赋值给doc如果存在且有ownerDocument属性那就是dom元素了这个值还是document如果不是dom元素比如普通的js对象的话那就把这个对象赋值给doc变量。紧接着对selector又进行了一个正则判断,这个正则也是在jQuery构造函数里面声明的目的是判断单标签 比如

这样的

 

  代码如下:

  // Match a standalone tag

  rsingleTag = /^<(w+)s*/?>(?:</1>)?$/,

  然后把结果交给ret变量,基于ret的值又进行划分按照单标签和复杂标签分开处理ret值存在那就是匹配到了单标签然后再根据context是不是普通对象又分为两种情况isPlainObject是检测是不是普通对象的方法,如果是普通对象,就利用js原生方法createElement传入标签创建元素并放在一个数组里面,之所以这样是为了以后跟jquery对象合并方便,然后把数组赋值给selector,后采用对象冒充的方法调用attr方法,这里attr居然有3个参数,而平常我们使用的api里面是两个参数,其实jQuery中有很多类似的情况,同样的方法有着对内对外两个接口。第二个参数就是对象形式的上下文,因为attr可以像

   代码如下:

  $("img").attr({ src: "test.jpg", alt: "Test Image" });

  这给我们的其实就是我们以后可以$(‘

',{id:'div'})这样写了也是支持的。如果不是对象就直接创建元素不考虑属性。还是把创建的元素放在数组里面。如果ret没有值那就是复杂的标签了比如$(‘
231
')这样的这个时候原生的js就搞不定啦需要调取另外一个方法jQuery.buildFragment来处理,这个方法实现以后在学习吧,总之最后都会创建dom元素。最后返回合并后的结果

 

   代码如下:

  return jQuery.merge( this, selector );

  不像之前的return this这里是返回merge执行后的结果其实他的任务就是把放在数组里面的创建好的的dom元素合并到jquery元素中去,最终变成{0:div,length:1...}这样的对象形式。这样的话简标签情况就处理完毕。

  然后else里面处理的是id的情况

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

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;

  很简单直接调用原生js的id选择器但是有一些系统会出现bug

  注释说的很清楚黑莓系统,就是元素已经不存在了但是依然能够匹配得到所以再加上父节点,不存在的元素肯定没有父节点的。还有一种情况就是ie和opera浏览器会出现按name值匹配的情况所以在做了一个判断

  if ( elem.id !== match[2] ) {

  如果真的不幸出现了那就不能使用原生方法而是用find方法也就是使用sizzle引擎了,在大多数正常情况下就直接将获取到的元素放到this里面就可以啦然后修改下context的值。Ok终于把第一个大分支分析完了。然后再看根据match的第二个分支

  ?

1
2
3

else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
}

  这里是如果没有上下文或者上下文是jquery对象的时候这个比较简单就是直接用find方法了rootjQuery 就是$(document)

  最后字符串的情况上面都不属于的话

   代码如下:

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

  This.constructor就是jQuery其实还是使用find方法。

  以上所述就是本文的全部内容了,希望大家能够喜欢。

时间: 2024-09-25 21:12:47

jQuery构造函数init参数分析续的相关文章

jQuery构造函数init参数分析续_jquery

如果selector是其他字符串情况就比较多了比较复杂了 // Handle HTML strings if ( typeof selector === "string" ) {...} 开始分不同的情况处理 // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 )

jQuery构造函数init参数分析_jquery

在我的上一篇随笔里面分析了jQuery的构造函数,jQuery对象中有一个原型方法init才是是真正的构造函数,通过init的原型对象跟jQuery的原型对象保持引用关系使得init的实例可以正常调用jQuery的原型方法,就好像是jQuery的实例一样.下面就来看看init这个幕后的构造函数是怎么写的: init: function( selector, context, rootjQuery ) { ... } 可以看到这个方法接受3个参数,其前两个参数是jQuery方法传递过来的 var

jQuery.prototype.init选择器构造函数源码思路分析_jquery

一.源码思路分析总结 概要: jQuery的核心思想可以简单概括为"查询和操作dom",今天主要是分析一下jQuery.prototype.init选择器构造函数,处理选择器函数中的参数: 这个函数的参数就是jQuery()===$()执行函数中的参数,可以先看我之前写的浅析jQuery基础框架一文,了解基础框架后,再看此文. 思路分析: 以下是几种jQuery的使用情况(用于查询dom),每种情况都返回一个选择器实例(习惯称jQuery对象(一个nodeList对象),该对象包含查询

jQuery学习笔记之jQuery.fn.init()的参数分析_jquery

从return new jQuery.fn.init( selector, context, rootjQuery )中可以看出参数selector和context是来自我们在调用jQuery方法时传过来的.那么selector和context都有哪些可能.   对于表格中的4~9行中的可能做具体分析. 如果selector是字符串,则首先检测是html代码还是#id.126行的if语句:以"<"开头,以">"结尾,且长度>=3.则假设额这个是HT

浅谈jQuery构造函数分析

  jquery的构造函数很好的运用的javascript的充分利用了JavsScript语言的动态性--对行参的类型和个数没有的严格要求,以至于一个函数可以实现多种功能需求,也为JavaScript语言的多态性提供了基础,在这个构造函数中,提供了六种不同的调用格式(根据官方API文档) 在我的上一篇文章里面 阐述了jQuery的大致框架,知道了所有代码都是写在了一个自调用匿名函数里面,并且传入了window对象,源码是这样的: ? 1 (function( window, undefined

浅谈jQuery构造函数分析_jquery

在我的上一篇文章里面 阐述了jQuery的大致框架,知道了所有代码都是写在了一个自调用匿名函数里面,并且传入了window对象,源码是这样的: (function( window, undefined ) {...})( window ); 我们通过alert(jquery) 知道它是一个对象,那么这个对象是怎么构造出来的呢?我们使用$(document)类似的写法获取元素,就好像直接调用了普通的方法一样,jQuery就是普通的函数吗?如果是构造函数为什么不是 new $(document)的常

jQuery技术内幕:深入解析jQuery架构设计与实现原理. 2.3 jQuery.fn.init( selector, context, rootjQuery )

2.3 jQuery.fn.init( selector, context, rootjQuery ) 2.3.1 12个分支 构造函数jQuery.fn.init()负责解析参数selector和context的类型,并执行相应的逻辑,最后返回jQuery.fn.init()的实例.参数selector和context共有12个有效分支,如表2-1所示. 表2-1 参数selector和context的12个分支          selector   context    示 例 1    

c++中拷贝构造函数的参数类型必须是引用

如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构 造函数.因此拷贝构造函数的参数必须是一个引用   在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识. 但是如果我问你"拷贝构造函数的参数为什么必须使用引用类型?"这个问题, 你会怎么回答? 或许你会回答为了

jQuery支持动态参数将函数绑定到事件上的方法

这篇文章主要介绍了jQuery支持动态参数将函数绑定到事件上的方法,实例分析了两种支持动态参数的函数绑定技巧,需要的朋友可以参考下     本文实例讲述了jQuery支持动态参数将函数绑定到事件上的方法.分享给大家供大家参考.具体分析如下: 下面的js代码提供了两种方法用于绑定函数到事件,其中方法二可以传递动态参数,非常实用 ? 1 2 3 4 5 6 7 8 9 //方法一 $('#foo').click(function(event) { alert('User clicked on "fo