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


Posted in Javascript onFebruary 05, 2013

一、源码思路分析总结
概要:
jQuery的核心思想可以简单概括为“查询和操作dom”,今天主要是分析一下jQuery.prototype.init选择器构造函数,处理选择器函数中的参数;
这个函数的参数就是jQuery()===$()执行函数中的参数,可以先看我之前写的浅析jQuery基础框架一文,了解基础框架后,再看此文。
思路分析:
以下是几种jQuery的使用情况(用于查询dom),每种情况都返回一个选择器实例(习惯称jQuery对象(一个nodeList对象),该对象包含查询的dom节点):
1、处理 $(""), $(null), $(undefined), $(false)
如果参数为以上非法值,jQuery对象不包含dom节点
2、处理 $(DOMElement)
如果参数为节点元素,jQuery对象包含该参数节点元素,并分别增加属性值为参数节点元素、1的context、length属性和用[]访问jQuery对象中dom节点的用法
例2.1:

var obj = document.getElementById('container'), 
jq = $(obj); console.log(jq.length); //1 
console.log(jq.context); //obj 
console.log(jq.[0]); //obj

3、处理$(HTML字符串)
如果第一个参数为HTML字符串,jQuery对象包含由jQuery.clean函数创建的fragment文档碎片中的childnodes节点
例3.1:
var jqHTML = $('<h1>文章标题</h1><p>内容</p>'); 
console.log(jqHTML); //[<h1>,<p>];

如果第一个参数(HTML字符串)为一个空的单标签,且第二个参数context为一个非空纯对象
例3.2:
var jqHTML = $('<div></div>', { class: 'css-class', data-name: 'data-val' }); console.log(jqHTML.attr['class']); //css-class 
console.log(jqHTML.attr['data-name']); //data-val

4、处理$(#id)
如果第一个参数是一个#加元素id,jQuery对象包含唯一拥有该id的元素节点,
并分别增加属性值为document、参数字符串、1、的context、selector、length属性和用[]访问jQuery对象中dom节点的用法
例4.1:
var jq = $('#container'); console.log(jq.[0]); //包含的dom节点元素 
console.log(jq.length); //1 
console.log(jq.context); //document 
console.log(jq.selector); //container

5、处理$(.className)
如果第一个参数是一个.className,jQuery对象中拥有class名为className的标签元素,并增加一个属性值为参数字符串、document的selector、context属性
实际执行代码为:
return jQuery(document).find(className);

6、处理$(.className, context)
如果第一个参数是.className,第二个参数是一个上下文对象(可以是.className(等同于处理$(.className .className)),jQuery对象或dom节点),
jQuery对象包含第二个参数上下文对象中拥有class名为className的后代节点元素,并增加一个context和selector属性
实际执行代码为:
return jQuery(context).find(className);

例6.1:
html代码:
<div class="main"> 
<h2 class="title">主内容标题</h2> 
<p>主标题</p> 
</div> 
<div class="sub"> 
<h2 class="title">次内容标题</h2> 
<p>次标题</p> 
</div>

JavaScript代码:
var jq, context; 
context = '.sub'; 
var jq = $('.title', context); 
console.log(jq.text()); //次内容标题 
console.log(jq.context); //document 
console.log(jq.selector); //.sub .title 
context = $('.sub'); 
var jq = $('.title', context); 
console.log(jq.text()); //次内容标题 
console.log(jq.context); //document 
console.log(jq.selector); //.sub .title 
context = $('.sub')[0]; 
var jq = $('.title', context); 
console.log(jq.text()); //次内容标题 
console.log(jq.context); //className为sub的节点元素 
console.log(jq.selector); //.title

7、处理$(fn)
如果第一个参数是fn函数,则调用$(document).ready(fn);
例7.1:
$(function(e){ 
console.log('DOMContent is loaded'); 
}) 
//上面代码等同于: 
jQuery(document).ready(function(e) { 
console.log('DOMContent is loaded'); 
});

8、处理$(jQuery对象)
如果第一个参数是jQuery对象,上面已经分析过如果在查询dom时,参数是一个#加元素id,返回的jQuery对象会增加一个属性值为参数字符串、document的selector、context属性
例8.1:
var jq = $('#container'); 
console.log(jq.selector); // #container 
console.log(jq.context); // document

那么当出现$($('#container'))该如何处理呢?同样的,返回的jQuery对象同情况5和6处理的情况一样
例8.2:
var jq2 = $($('#container')); 
console.log(jq2.selector); // #container 
console.log(jq2.context); // document

二、源码注释分析
[ 基于jQuery1.8.3 ]
var rootjQuery = $(document), 
rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/; 
jQuery.fn = jQuery.prototype = { 
init: function( selector, context, rootjQuery ) { 
var match, elem, ret, doc; 
// Handle $(""), $(null), $(undefined), $(false) 
if ( !selector ) { 
return this; 
} 
// Handle $(DOMElement) 
if ( selector.nodeType ) { 
this.context = this[0] = selector; 
this.length = 1; 
return this; 
} 
// Handle HTML strings 
if ( typeof selector === "string" ) { 
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 ); 
} 
// Match html or make sure no context is specified for #id 
// match[1]不为null,则为html字符串,match[2]不为null,则为元素id 
if ( match && (match[1] || !context) ) { 
// HANDLE: $(html) -> $(array) 
if ( match[1] ) { 
context = context instanceof jQuery ? context[0] : context; 
doc = ( context && context.nodeType ? context.ownerDocument || context : document ); 
// scripts is true for back-compat 
// selector是由文档碎片中的childnodes组成的数组 
selector = jQuery.parseHTML( match[1], doc, true ); 
// 如果match[1]为空的单标签元素(如:<div><div>)且context为对象字面量 
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 
// 如果context对象不为空,则将对象中的属性添加到selector数组中仅有的dom节点中 
this.attr.call( selector, context, true ); 
} 
// merge函数的参数应该为两个数组,目的是将第二个数组中的项合并到第一个数组,而this并不是一个数组, 
// this是选择器init构造函数的实例对象,该对象继承jQuery.prototype对象中的length属性(默认为0),因此可以理解好merge函数源码 
// 将selector中的dom项合并到this对象中,并返回该对象 
return jQuery.merge( this, selector ); 
// 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 
// ie6,7和Opera存在此bug,当一个标签name和一个标签id值相等时, 
// document.getElementById(#id)函数将返回提前出现的标签元素 
if ( elem.id !== match[2] ) { 
// 如果存在以上Bug,则返回由find函数返回的document文档的后代元素集合 
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; 
} 
// HANDLE: $(expr, $(...)) 
// context不存在或者context为jQuery对象 
} else if ( !context || context.jquery ) { 
return ( context || rootjQuery ).find( selector ); 
// HANDLE: $(expr, context) 
// (which is just equivalent to: $(context).find(expr) 
// context为className或者dom节点元素 
} else { 
// 等同于jQuery(context).find(selector) 
return this.constructor( context ).find( selector ); 
} 
// 处理$(fn)===$(document).ready(fn) 
} else if ( jQuery.isFunction( selector ) ) { 
return rootjQuery.ready( selector ); 
} 
// 处理$(jQuery对象) 
if ( selector.selector !== undefined ) { 
this.selector = selector.selector; 
this.context = selector.context; 
} 
// 当第一个参数selector为jQuery对象时,将selector中的dom节点合并到this对象中,并返回this对象 
return jQuery.makeArray( selector, this ); 
} 
}
Javascript 相关文章推荐
Js+XML 操作
Sep 20 Javascript
JavaScript 动态生成方法的例子
Jul 22 Javascript
JQuery中使用.each()遍历元素学习笔记
Nov 08 Javascript
jQuery类选择器用法实例
Dec 23 Javascript
深入理解事件冒泡(Bubble)和事件捕捉(capture)
May 28 Javascript
node.js学习之交互式解释器REPL详解
Dec 08 Javascript
Require.js的基本用法详解
Jul 03 Javascript
vue中如何让子组件修改父组件数据
Jun 14 Javascript
JavaScript学习笔记之数组基本操作示例
Jan 09 Javascript
JS使用cookie保存用户登录信息操作示例
May 30 Javascript
6种JavaScript继承方式及优缺点(小结)
Feb 06 Javascript
使用JS实现动态时钟
Mar 12 Javascript
jQuery不间断滚动效果(模拟百度新闻支持文字/图片/垂直滚动)
Feb 05 #Javascript
得到jQuery detach()后节点中的某个值实现代码
Feb 05 #Javascript
jquery zTree异步加载简单实例分享
Feb 05 #Javascript
JS打印gridview实现原理及代码
Feb 05 #Javascript
漂亮的jquery提示效果(仿腾讯弹出层)
Feb 05 #Javascript
Js 获取Gridview选中行的内容操作步骤
Feb 05 #Javascript
6款经典实用的jQuery小插件及源码(对话框/提示工具等等)
Feb 04 #Javascript
You might like
快速开发一个PHP扩展图文教程
2008/12/12 PHP
PHP入门之常量简介和系统常量
2014/05/12 PHP
PHP通过插入mysql数据来实现多机互锁实例
2014/11/05 PHP
php学习笔记之基础知识
2014/11/08 PHP
Yii实现文章列表置顶功能示例
2016/10/18 PHP
PHP获取input输入框中的值去数据库比较显示出来
2016/11/16 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
2017/02/15 PHP
老生常谈PHP 文件写入和读取(必看篇)
2017/05/22 PHP
国外大牛IE版本检测!现在IE都到9了,IE检测代码
2012/01/04 Javascript
javascript解析json数据的3种方式
2014/05/08 Javascript
D3.js 从P元素的创建开始(显示可加载数据)
2014/10/30 Javascript
jQuery中outerWidth()方法用法实例
2015/01/19 Javascript
jQuery实现鼠标经过弹出提示信息的地图热点效果
2015/08/07 Javascript
javascript闭包(Closure)用法实例简析
2015/11/30 Javascript
基于JQuery打造无缝滚动新闻步骤详解
2016/03/31 Javascript
SWFUpload多文件上传及文件个数限制的方法
2016/05/31 Javascript
JS实现颜色梯度与渐变效果完整实例
2016/12/30 Javascript
JS实现给对象动态添加属性的方法
2017/01/05 Javascript
vue-resource 拦截器使用详解
2017/02/21 Javascript
关于vue路由缓存清除在main.js中的设置
2019/11/06 Javascript
解决vuex数据异步造成初始化的时候没值报错问题
2019/11/13 Javascript
JS猜数字游戏实例讲解
2020/06/30 Javascript
layui使用及简单的三级联动实现教程
2020/12/01 Javascript
JS实现页面侧边栏效果探究
2021/01/08 Javascript
[08:38]DOTA2-DPC中国联赛 正赛 VG vs Elephant 选手采访
2021/03/11 DOTA
浅谈flask源码之请求过程
2018/07/26 Python
Django rest framework jwt的使用方法详解
2019/08/08 Python
Django中密码的加密、验密、解密操作
2019/12/19 Python
Django Admin设置应用程序及模型顺序方法详解
2020/04/01 Python
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
法国足球商店:Footcenter
2019/07/06 全球购物
幼儿园国庆节活动方案
2014/02/01 职场文书
小学生节约用水倡议书
2014/05/15 职场文书
学习十八届四中全会精神思想汇报
2014/10/23 职场文书
2016年校园社会综合治理宣传月活动总结
2016/03/16 职场文书
Django开发RESTful API实现增删改查(入门级)
2021/05/10 Python