jQuery源码阅读笔记(96-283行)

来源:互联网 发布:在线查看网站js源代码 编辑:程序博客网 时间:2024/05/21 09:40

jQuery(版本2.0.3)在96-283行中给JQ对象,添加一些方法和属性

下载地址:https://code.jquery.com/jquery/

版权声明:以下为本人在妙味课堂听课的笔记

96-283行大体结构如下:

jQuery.fn = jQuery.prototype = {  //添加实例属性和方法jquery : 版本constructor : 修正指向问题init() : 初始化和参数管理init大体框架:init:function(){if(1、$(""), $(null), $(undefined), $(false)){return this;//}if(2、$('#XXX') $('.XXX') $('XXX')  $('#XXX XXX')根据类、范围、标签类型或者id选择;3、$('<XXX>') $('<XXX>123') $('<XX>X</XX><XX>2</XX>')创建标签){if($('<XXX>')或者$('<XX>X</XX><XX>2</XX>')){match = [ null, '<XXX>', null ];或者match = [ null, '<XX>X</XX><XX>2</XX>', null ];}else(){如果参数为$('#XXX'),match=['#XXX',null,'XXX'];    如果参数为$('<XXX>123'),match=['<XXX>123','<XXX>,null]';    否则,match=null;}if($('<XXX>') || $('<XX>X</XX><XX>2</XX>') || $('<XXX>123') || $('#XXX')){if($('<XXX>') || $('<XX>X</XX><XX>2</XX>') || $('<XXX>123')){parseHTML将参数字符串转成数组,每个标签为数组的一项,if($('<XXX>',{attr:v})){创建出标签对象;if(如果属性有对应方法的话,调用方法){添加属性;}else{如果属性没有对应的方法则通过attr进行操作;}return this;返回创建出来的标签;}}else{如果是根据id选择的话,返回id筛选出的元素;}}else if(是$(expr, $(...))这种复杂选择器的话){丢给find()函数处理;}else if(是$(expr, 原生的js对象)这种复杂选择器的话){丢给find()函数处理;}}else if(如果是节点的话,比如document,window等){将上下文和json对象同时指向该节点对象,并返回对象;}else if(5、$(function(){})){返回document.ready(selector),比如$(fucntion(){DOM元素加载完再执行函数体});}if(有人强行要写成$($('#div'))的话){重新说明下指向就好了}return $([])、$({})处理后返回的jason}selector : 存储选择字符串length : this对象的长度toArray() :  转数组get() :  转原生集合pushStack() :  JQ对象的入栈each() :  遍历集合ready() :  DOM加载的接口slice() :  集合的截取first() :  集合的第一项last() :   集合的最后一项eq() :   集合的指定项map() :   返回新集合end() :   返回集合前一个状态push() :    (内部使用)sort() :    (内部使用)splice() :  (内部使用)};

详细讲解

jQuery.fn = jQuery.prototype = {// The current version of jQuery being usedjquery: core_version,constructor: jQuery,/*constructor用于修正指向问题,原生js中我们创建出来一个类之后,会自动在该类的原型中加入constructor属性指向自身的构造函数(详细讲解见:http://www.jb51.net/article/22334.htm)但是constructor非常容易被修改,当类的prototype被覆盖时,如Aaa.prototype = {constructor : Aaa,name : 'hello',age : 30};此时类Aaa将指向Object,所以在这边重新指向下*/init: function( selector, context, rootjQuery ) {//三个参数分别为:选择器,上下文,documentvar match, elem;/*我们jQuery时,参数可以分为以下几类:可参考http://www.w3school.com.cn/jquery/core_jquery.asphttp://www.w3school.com.cn/jquery/jquery_ref_selectors.asp1、$(""), $(null), $(undefined), $(false)2、$('#XXX') $('.XXX') $('XXX')  $('#XXX XXX')根据类、范围、标签类型或者id选择3、$('<XXX>') $('<XXX>123') $('<XX>X</XX><XX>2</XX>')创建标签4、$(this)  $(document) $(window)5、$(function(){}):全写为 jQuery(document).ready(function(){ }); 表示dom元素加载完再执行函数体6、$([])  $({})*/// HANDLE: $(""), $(null), $(undefined), $(false)//这边用于处理第一种情况,当参数不符合要求时直接返回if ( !selector ) {return this;}// Handle HTML stringsif ( 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 checkmatch = [ null, selector, null ];//如果参数符合第三种情况中的$('<XXX>')或者$('<XX>X</XX><XX>2</XX>'),也就是创建标签的时候} else {match = rquickExpr.exec( selector );/*rquickExpr可以匹配$('#XXX'),'<XXX>123'。exec方法用于匹配正则,如果能匹配到,返回值为[匹配的字符串本身,第一个组,第二个组。。。],如果不能匹配,则返回null*/}// Match html or make sure no context is specified for #id:创建标签,或者通过没有上下文来判断id,即$('<XXX>') || $('<XX>X</XX><XX>2</XX>') || $('#XXX') || $('<XXX>123')if ( match && (match[1] || !context) ) {// HANDLE: $(html) -> $(array)if ( match[1] ) {context = context instanceof jQuery ? context[0] : context;//得到原生的document// scripts is true for back-compatjQuery.merge( this, jQuery.parseHTML(//parseHTML将字符串转成节点数组,jQuery.parseHTML('<li>1</li><li>2</li>',document,true); 返回['li','li'],其中第二个参数表示上下文,第三个参数表示是否允许字符串中的script标签添加进来/*merge在jq内部允许json合并,$('<li>1</li><li>2</li>')在jq源码中会生成,this = {0 : 'li',1 : 'li',length : 2}这样一个json对象(可以自己调用输出下$(‘div’)或其他的进行试验),merge用于将得到的数组转化成json对象,便于后续处理。如$('<li>1</li><li>2</li>').css('background','#000'),会进行for循环处理每个lifor(var i=0;i<this.length;i++){this[i].style.background = 'red';}*/match[1],context && context.nodeType ? context.ownerDocument || context : document,true) );// HANDLE: $(html, props)创建的标签带有属性时,如:$('<li></li>',{title : 'hi',html : 'abcd',css : {background:'red'}}).appendTo( 'ul' );if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {for ( match in context ) {//如果属性有对应的方法// Properties of context are called as methods if possibleif ( jQuery.isFunction( this[ match ] ) ) {this[ match ]( context[ match ] );// ...and otherwise set as attributes} else {//如果属性没有对应的方法则通过attr进行操作this.attr( match, context[ match ] );}}}//返回创建出来的标签对象return this;// HANDLE: $(#id)} else {elem = document.getElementById( match[2] );//如果参数为$('#XXX'),match=['#XXX',null,'XXX'];缩略版中已讲。所以此处match[2]正好是元素的id// Check parentNode to catch when Blackberry 4.6 returns// nodes that are no longer in the document #6963if ( elem && elem.parentNode ) {//elem.parentNode主要用于处理黑莓浏览器的一个问题// Inject the element directly into the jQuery objectthis.length = 1;this[0] = elem;/*上文中已说过,jq源码中获取或生成的元素以this = {0 : 'li',1 : 'li',length : 2}这样一个json对象存储,初始化时length为0,在获取到对象之后重新赋值*/}this.context = document;this.selector = selector;return this;}// HANDLE: $(expr, $(...))} else if ( !context || context.jquery ) {//$('ul',$(document)).find('li');当传入的context为jq对象时return ( context || rootjQuery ).find( selector );// HANDLE: $(expr, context)// (which is just equivalent to: $(context).find(expr)} else {//$('ul',document).find('li');当传入的context为原生元素时return this.constructor( context ).find( selector );}// 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 ) {//$($('#div'))this.selector = selector.selector;this.context = selector.context;}return jQuery.makeArray( selector, this );/*将$([]) $({})中传入的对象做处理,返回this = {0 : 'li',1 : 'li',length : 2}这样一个json对象存储,与上文中merge函数相似*/},// Start with an empty selectorselector: "",// The default length of a jQuery object is 0length: 0,toArray: function() {return core_slice.call( this );/*上文中core_slice = core_deletedIds.slice将数组的slice方法存储在core_slice中,所以toArray的作用就是将对象转化成一个原生的数组。比如页面上有三个div,那么$('div')得到的是 { 0 : div , 1 : div , 2 : div , length : 3 }$('div') : { 0 : div , 1 : div , 2 : div , length : 3 }$('div').toArray() 得到的是 [div,div,div]*/},// Get the Nth element in the matched element set OR// Get the whole matched element set as a clean arrayget: function( num ) {return num == null ?// Return a 'clean' arraythis.toArray() :// Return just the object( num < 0 ? this[ this.length + num ] : this[ num ] );/*$('div').get()返回原生数组(调用了toArray方法,),$('div').get(num),返回第num个元素(原生的)。值得注意的是,这边的this[ num ]是指this.0,this.1,this.2...原生js中规定,取得元素属性的时候有两种方法,一种是. ,当属性名是变量是可以使用[]*/},// Take an array of elements and push it onto the stack// (returning the new matched element set)pushStack: function( elems ) {/*入栈处理,学过数据结构的朋友都应该了解栈这个概念。栈的特点就是后入先出。此函数在内部调用较多。举个例子:$('div').find('span').css('background','red').end().css('background','yellow');执行$('div').find('span')时$('div')先入栈,span再入栈(所以是span先出栈div再出栈),所以css方法执行时是针对的span。如果我们想要对栈的下一层(也就是先入栈的div)操作,可以使用end方法回溯到栈的下一层,使当前对象指向div。栈的操作不仅为jq中很多链式操作提供了便利,也为jq整体提供了清晰的结构和逻辑*/// Build a new jQuery matched element setvar ret = jQuery.merge( this.constructor(), elems );//给新入栈的元素添加一个prev属性,为end方法做准备,便于回溯// Add the old object onto the stack (as a reference)ret.prevObject = this;ret.context = this.context;// Return the newly-formed element setreturn ret;},// Execute a callback for every element in the matched set.// (You can seed the arguments with an array of args, but this is// only used internally.)each: function( callback, args ) {return jQuery.each( this, callback, args );},ready: function( fn ) {// Add the callbackjQuery.ready.promise().done( fn );return this;},slice: function() {//将切割后的数组push到栈中return this.pushStack( core_slice.apply( this, arguments ) );//apply方法详解见http://blog.csdn.net/business122/article/details/8000676},first: function() {return this.eq( 0 );},last: function() {return this.eq( -1 );},eq: function( i ) {//将eq得到的元素push进栈并返回var len = this.length,j = +i + ( i < 0 ? len : 0 );return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );/*前边说过,jq中获取到的集合存储形式为:{0:XXX,1:YYY,length:2},所以这边直接返回this[j]就好了*/},map: function( callback ) {//遍历数组或jason等集合中的key和valuereturn this.pushStack( jQuery.map(this, function( elem, i ) {return callback.call( elem, i, elem );}));},end: function() {//回溯到栈的下一层return this.prevObject || this.constructor(null);},// For internal use only.// Behaves like an Array's method, not like a jQuery method.push: core_push,sort: [].sort,splice: [].splice};



0 0