摘要:节点修改对象的属性,这就相当于把对象转成了一个类数组,最后返回,可用于链式调用。如果传入的是单标签,且第二个参数是一个纯对象例如则把后面对象的属性一一添加到创建的这个节点的属性上。
我们先看看jQuery的原型中初始化了哪些属性和方法:
jQuery.fn = jQuery.prototype = { jquery: core_version, //jquery版本号 constructor: jQuery, //构造器指向 init: //jquery的入口函数,主要用来实现选择器和DOM节点的创建 selector: //将选择器进行存储 length: //当前选择器存储的DOM节点的个数 toArray: //通过方法借调的方式,把一个类数组对象转换为一个数组 //类数组对象就是指有数字作为属性,且有length属性,jQuery是一个类数组对象,arguments也是。 get: //获取jQuery对象中的某一个DOM节点,返回的是一个DOM节点, pushStack: //将一个DOM元素集合加入到jQuery对象的prevObject中。 //this.prevObject=this,让当前DOM集合存储到prevObject属性中,方便end()调用是回溯。 each: //对数组进行遍历 ready: //当DOM树加载完毕后,回调该函数 slice: //类似于toArray方法,只是该方法会进行一次pushStack操作 first: //返回第一个元素的jQuery对象 last: //返回最后一个元素的jQuery对象 eq: //传入一个数字num,获取第num个元素的jQuery对象 map: //map将一个数组中的元素转换到另一个数组中,可以传入一个回调函数,作用与each类似,只是map会返回一个新的数组,而each不会 end: //返回调用parent()、find()、filter()等方法之前的jQuery对象,就是回溯到上一个DOM合集 push: core_push, //存储了数组的push方法 sort: [].sort, //存储了数组的sort方法 splice: [].splice //存储了数组的splice方法 }
上面是对jQuery初始化的一些方法和属性的介绍,前面初始化jQuery对象时,我们可以看到jQuery对象其实是一个实例化的jQuery.fn.init,所以这里主要看下init是如何实现,其余的方法在具体用到的时候再看。
首先可以观察到init方法传入了三个参数:
init: function( selector, context, rootjQuery ) {...}
selector(选择器)
context(上下文环境)
rootJQuery( $(document) )
rootjQuery = jQuery(document);//参见866行
init对传入的选择器进行了以下的区分:
空 : 包括 "" false undefined null
if ( !selector ) {return this;}
string:这个部分判断有点复杂,会在后面详细的介绍。
if ( typeof selector === "string" )...
DOM节点:修改jQuery对象的属性 0:selector,length:1 ;这就相当于把jQuery对象转成了一个类数组,最后返回this,可用于链式调用。
if ( selector.nodeType ){//通过判断该变量是否有nodeType属性来确定是不是一个DOM节点
this.context = this[0] = selector;
this.length = 1;
return this;}
Function: $(fn) 就相当于 $(document).ready(fn)
if ( jQuery.isFunction( selector ){//jquery内部用来判断一个对象是不是一个函数的方法 return rootjQuery.ready( selector );}
jQuery对象:
if ( selector.selector !== undefined ) {//如果改变了有select属性则认为该变量是jQ变量 this.selector = selector.selector; this.context = selector.context; return jQuery.makeArray( selector, this );}
其他任意类型的值:将传入的变量和jQuery对象合并成一个数组
return jQuery.makeArray( selector, this );
下面我们来看当 selector 为一个字符串时是如何进行处理的:
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {//匹配单标签 match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } if ( match && (match[1] || !context) ) { //如果是字符串是html标签 if ( match[1] ) { jQuery.merge( this, jQuery.parseHTML(match[1]) ); //先通过parseHTML将字符串转换成DOM对象的数组,然后通过merge将DOM对象的数组合并到this上。 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 如果传入的是单标签,且第二个参数是一个纯对象,例如: $("",{"id":"box", "class":"red"})//则把后面对象的属性一一添加到创建的这个DOM节点的属性上。 //现在知道了通过$不仅可以创建标签,还能在创建单标签的时候直接在后面写属性。 } } else { //如果是"#id",直接通过js的原生方法getElementById获取DOM节点 elem = document.getElementById( match[2] ); } //后面的情况都是通过find方法来找复杂的选择器。例如selector是一个".ClassName" //具体过程为jQuery.fn.find->jQuery.find->Sizzle //最后会调用Sizzle方法,这是jQuery选择器的核心方法,是一个独立的引擎,等到了后面我看懂了再告诉大家吧 (逃 } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); } else { return this.constructor( context ).find( selector ); }看这段代码前我们要先弄懂match到底是什么东西
rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]*))$/; (75行) match = rquickExpr.exec( selector ); (116行)exec方法用于正则匹配,返回一个数组,第一个元素是匹配到的字符串,后面的元素为匹配子项,具体用法。
举个栗子:
var rquickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]*))$/; console.log( match = rquickExpr.exec( "" ) ); // ["
", "
", undefined] console.log( match = rquickExpr.exec( "#id" ) ); // ["#id", undefined, "id"]
现在我们知道了,match其实就是存储了字符串含义的数组,不得不感叹这是人想出来的吗。正则懵逼。
如果match[1]存在就代表是html标签
如果match[2]存在就代表是id名
如果两种情况都没有匹配到的话,表示这是一个复杂选择器,具体的实现是jQuery内部的Sizzle方法来实现,这个方法有两千行左右,可谓是jQuery的核心,而且jQuery把这个方法也当成了一个多带带的库,如果觉得jQuery太大,只会用到选择器部分的功能,感兴趣的话可以在Sizzle官网 下载
可以看到我们平时调用 $() 的时候很爽,又能当选择器又能创节点,但是不知道这后面的实现方法原来这么复杂,还真是用起来越方便的东西实现越复杂。
恩,楼上说的对 -。-
感兴趣的话可以看看我的github,不妨给个star。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/86700.html
摘要:的缓存机制来看看中提高的数据缓存机制,有两个函数,分别是和,可以看出来,一个是在对象上,一个是在生成的对象上。而且从源码来看,的缓存机制自带清内存操作,更是锦上添花呀。参考源码分析数据缓存本文在上的源码地址,欢迎来。 欢迎来我的专栏查看系列文章。 不打算介绍 deferred,或者放到后面以后去介绍,因为我对于 js 的异步存在着恐惧,看了半天代码,发现,用挺好用的,一看源码,全傻眼了...
摘要:的指向的是对象,所以此时扩展的是对象,可以直接通过的方式调用。 写过jquery插件的人都知道可以通过jquery提供的extend可以对jquery对象进行扩展,而且该方法不仅可以对jquery对象扩展,还能给一个对象添加新的属性和方法,这个在后面会介绍。 通过不同的方式调用extend扩展的方法也不同: 通过 $.extend() 扩展的是静态方法; 而通过 $.fn.exten...
摘要:而在构造函数中,返回了的实例对象。在中直接返回过的实例,这里的是的真正构造函数最后对外暴露入口时,将字符与对等起来。因此当我们直接使用创建一个对象时,实际上是创建了一个的实例,这里的正真构造函数是原型中的方法。 showImg(https://segmentfault.com/img/remote/1460000008749398); 早几年学习前端,大家都非常热衷于研究jQuery源...
摘要:到目前为止,的贡献者团队共名成员,多条,可想而知,是一个多么庞大的项目。参考源码分析整体架构源码解析读书笔记第二章构造对象函数详解本文在上的源码地址,欢迎来。 欢迎来我的专栏查看系列文章。 决定你走多远的是基础,jQuery 源码分析,向长者膜拜! 我虽然接触 jQuery 很久了,但也只是局限于表面使用的层次,碰到一些问题,找到 jQuery 的解决办法,然后使用。显然,这种做法的...
摘要:本来想学习一下的源码,但由于的源码有多行,设计相当复杂,所以决定从开始,分析一个成熟的框架的代码结构及执行步骤。同时发表在我的博客源码分析代码结构 本来想学习一下jQuery的源码,但由于jQuery的源码有10000多行,设计相当复杂,所以决定从zepto开始,分析一个成熟的框架的代码结构及执行步骤。 网上也有很多zepto的源码分析,有的给源码添加注释,有的谈与jQuery的不同,...
阅读 3167·2021-09-06 15:02
阅读 2211·2019-08-30 15:48
阅读 3391·2019-08-29 11:08
阅读 3246·2019-08-26 13:55
阅读 2400·2019-08-26 13:35
阅读 3125·2019-08-26 12:11
阅读 2566·2019-08-26 11:48
阅读 844·2019-08-26 11:42