导航:首页 > 源码编译 > jquery源码分析aaron

jquery源码分析aaron

发布时间:2022-05-10 18:37:27

1. 那些年一直用jQuery处理事件,这些年想了解下内部原理吗

说起jQuery的事件,不得不提一下Dean Edwards大神 addEvent库,很多流行的类库的基本思想从他那儿借来的

jQuery的事件处理机制吸取了javaScript专家Dean Edwards编写的事件处理函数的精华,使得jQuery处理事件绑定的时候相当的可靠。

在预留退路(graceful degradation),循序渐进以及非入侵式编程思想方面,jQuery也做的非常不错

事件的流程图

总的来说对于JQuery的事件绑定

在绑定的时候做了包装处理

在执行的时候有过滤器处理

.on( events [, selector ] [, data ], handler(eventObject) )

events:事件名

selector : 一个选择器字符串,用于过滤出被选中的元素中能触发事件的后代元素

data :当一个事件被触发时,要传递给事件处理函数的

handler:事件被触发时,执行的函数

例如:

var body = $('body')
body.on('click','p',function(){
console.log(this)
})

用on方法给body上绑定一个click事件,冒泡到p元素的时候才出发回调函数

这里大家需要明确一点:每次在body上点击其实都会触发事件,但是只目标为p元素的情况下才会触发回调handler

通过源码不难发现,on方法实质只完成一些参数调整的工作,而实际负责事件绑定的是其内部jQuery.event.add方法

on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
var origFn, type;
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
// ( types-Object, selector, data )
if ( typeof selector !== "string" ) {
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for ( type in types ) {
this.on( type, selector, data, types[ type ], one );
}
return this;
}
if ( data == null && fn == null ) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
if ( fn === false ) {
fn = returnFalse;
} else if ( !fn ) {
return this;
}
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
// Can use an empty set, since event contains the info
jQuery().off( event );
return origFn.apply( this, arguments );
};
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
return this.each( function() {
jQuery.event.add( this, types, fn, data, selector );
});

针对事件处理,我们可以拆分2部分:

一个事件预绑定期

一个事件执行期

本章着重讲解事件的预绑定的时候做了那些处理,为什么要这样处理?

事件底层的绑定接口无非就是用addEventListener处理的,所以我们直接定位到addEventListener下面

jQuery.event.add 中有

elem: 目标元素

type: 事件类型,如’click’

eventHandle: 事件句柄,也就是事件回调处理的内容了

false: 冒泡

现在我们把之前的案例给套一下看看

var body = document.getElementsByTagName('body')
var eventHandle = function(){
console.log(this)
}
body .addEventListener( 'click’, eventHandle, false );

明显有问题,每次在body上都触发了回调,少了个p元素的处理,当然这样的效果也无法处理

eventHandle源码

回到内部绑定的事件句柄eventHandle ,可想而知eventHandle不仅仅只是只是充当一个回调函数的角色,而是一个实现了EventListener接口的对象

if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
eventHandle.elem = elem;
}

可见在eventHandle中并没有直接处理回调函数,而是映射到jQuery.event.dispatch分派事件处理函数了

仅仅只是传入eventHandle.elem,arguments , 就是body元素 与事件对象

那么这里有个问题,事件回调的句柄并没有传递过去,后面的代码如何关联?

本章的一些地方可能要结合后面的dispatch处理才能理清,但是我们还是先看看做了那些处理

on内部的实现机制

我们开从头来理清下jQuery.event.add代码结构,适当的跳过这个环节中不能理解的代码,具体遇到在提出

之前就提到过jQuery从1.2.3版本引入数据缓存系统,贯穿内部,为整个体系服务,事件体系也引入了这个缓存机制

所以jQuery并没有将事件处理函数直接绑定到DOM元素上,而是通过$.data存储在缓存$.cahce上

第一步:获取数据缓存

//获取数据缓存
elemData = data_priv.get( elem );

在$.cahce缓存中获取存储的事件句柄对象,如果没就新建elemData

第二步:创建编号

if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}

为每一个事件的句柄给一个标示,添加ID的目的是 用来寻找或者删除handler,因为这个东东是缓存在缓存对象上的,没有直接跟元素节点发生关联

第三步:分解事件名与句柄

if ( !(events = elemData.events) ) {
events = elemData.events= {};
}
if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
eventHandle.elem = elem;
}

events,eventHandle 都是elemData缓存对象内部的,可见

在elemData中有两个重要的属性,

一个是events,是jQuery内部维护的事件列队

一个是handle,是实际绑定到elem中的事件处理函数

之后的代码无非就是对这2个对象的筛选,分组,填充了

第四步: 填充事件名与事件句柄

// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
// 事件可能是通过空格键分隔的字符串,所以将其变成字符串数组
// core_rnotwhite:/\S+/g
types = ( types || "" ).match( core_rnotwhite ) || [""];
// 例如:'.a .b .c'.match(/\S+/g) → [".a", ".b", ".c"]
// 事件的个数
t = types.length;
while ( t-- ) {
// 尝试取出事件的命名空间
// 如"mouseover.a.b" → ["mouseover.a.b", "mouseover", "a.b"]
tmp = rtypenamespace.exec( types[t] ) || [];
// 取出事件类型,如mouseover
type = origType = tmp[1];
// 取出事件命名空间,如a.b,并根据"."分隔成数组
namespaces = ( tmp[2] || "" ).split( "." ).sort();
// There *must* be a type, no attaching namespace-only handlers
if ( !type ) {
continue;
}
// If event changes its type, use the special event handlers for the changed type
// 事件是否会改变当前状态,如果会则使用特殊事件
special = jQuery.event.special[ type ] || {};
// If selector defined, determine special event api type, otherwise given type
// 根据是否已定义selector,决定使用哪个特殊事件api,如果没有非特殊事件,则用type
type = ( selector ? special.delegateType : special.bindType ) || type;
// Update special based on newly reset type
// type状态发生改变,重新定义特殊事件
special = jQuery.event.special[ type ] || {};
// handleObj is passed to all event handlers
// 这里把handleObj叫做事件处理对象,扩展一些来着handleObjIn的属性
handleObj = jQuery.extend({
type: type,
origType: origType,
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join(".")
}, handleObjIn );
// Init the event handler queue if we're the first
// 初始化事件处理列队,如果是第一次使用,将执行语句
if ( !(handlers = events[ type ]) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
// Only use addEventListener if the special events handler returns false
// 如果获取特殊事件监听方法失败,则使用addEventListener进行添加事件
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
}
}
}
// 特殊事件使用add处理
if ( special.add ) {
special.add.call( elem, handleObj );
// 设置事件处理函数的ID
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
// Add to the element's handler list, delegates in front
// 将事件处理对象推入处理列表,姑且定义为事件处理对象包
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
// Keep track of which events have ever been used, for event optimization
// 表示事件曾经使用过,用于事件优化
jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
// 设置为null避免IE中循环引用导致的内存泄露
elem = null;
},

这段比较长了分解下,最终的目的就是为填充events,eventHandle

2. 那些年用jquery处理事件,这些年想知道内部原理吗

说起jQuery的事件,不得不提一下Dean Edwards大神 addEvent库 ,很多流行的类库的基本思想从他那儿借来的

jQuery的事件处理机制吸取了JavaScript专家Dean Edwards编写的事件处理函数的精华,使得jQuery处理事件绑定的时候相当的可靠。

在预留退路(graceful degradation),循序渐进以及非入侵式编程思想方面,jQuery也做的非常不错

总的来说对于JQuery的事件绑定

在绑定的时候做了包装处理

在执行的时候有过滤器处理

.on( events [, selector ] [, data ], handler(eventObject) )

selector : 一个选择器字符串,用于过滤出被选中的元素中能触发事件的后代元素

data :当一个事件被触发时,要传递给事件处理函数的

handler:事件被触发时,执行的函数

var body = $('body')
body.on('click','p',function(){
console.log(this)
})
用on方法给body上绑定一个click事件,冒泡到p元素的时候才出发回调函数

这里大家需要明确一点: 每次在body上点击其实都会触发事件,但是只目标为p元素的情况下才会触发回调handler

通过源码不难发现,on方法实质只完成一些参数调整的工作,而实际负责事件绑定的是其内部jQuery.event.add方法,转载,仅供参考。

3. jquery有两个版本,分别是proction和development,请问两者之间的的区别是什么

一个用在生产环境,也就是正式的线上,代码是压缩过的,应一个没压缩,你可以分析学习jquery源代码!

4. JQuery的源码看过吗能不能简单说一下它的实现原理

没别的,就是封装javascript,使调用更简单而已。

5. 如何高效地阅读 jQuery 源码

尝试把jquery拆分为ecma扩展(以及emitter promise和queue),dom兼容性问题(compressed && gziped 小于14k,尝试理解哪些函数我不提供兼容性就不能使用,哪些我可以接受原生写法,同时包括一个自己写的css3选择器) , 链式调用(尝试理解用户需求,理解怎么写方便),动画库(你是不是可以jq和css3兼容呢)

6. 各位大侠们,我正在学习jquery,但是当学到Ajax的时候感觉完全找不到头绪,希望各位给指点一下啊

什么都不用,只要jquery开发文档api就好了,我就是这样学过来的

7. jquery源码 ,jquery选择器,javascript,正则表达式

quickExpr应该是个二义正则。前半段是:
^[^<]*(<[\w\W]+>)[^>]*$:我猜测意思是一个简单的标签。如$('<div>new Div</div>')匹配的用法。
后半段是:
^#([\w-]+)$:这个显然就是id选择器。->getElementById
注意两个正则用了|来分隔二义,所以你这里的匹配不成功是正常的。
jquery应该是根据这个quickExpr来判断
if(match[1]) createNewfragment();....
else if(match[2]) getElementById();
当然这只是个人猜测,没有细读jquery源码。仅做参考

8. 如何正确阅读jquery源码和jquery插件源码

1. jQuery 里面有很多东西是出于兼容性,历史遗留。

比如 .ready() 之类的函数,为什么会很scroll 有关,那是为了兼容某些ie。这种代码对于编程思想来说不仅没用,而且是杂音,你要筛选出来就得了解这段代码的变动,费心费力得不偿失。

2. jQuery 里面的代码不一定是最优的,例如事件委托,每一次事件触发都要调用选择器,实际上是效率很低的。但是我又比较懒,没有提交patch。

3. jQuery 实际上很容易写出来一个 barebone alternative,在使用的过程中多想,多思考多总结就可以了。

4. jQuery 这类框架里真正有思维挑战性的东西不多,一半以上是堆代码而已,剩下的一点价值在于架构、抽象、扩展能力。

5. 我有一句话与所有的同行分享:工程师让需求成为现实,优秀工程师化复杂为简单,顶尖工程师变不可能为可能;架构师掌握现在,优秀架构师展望未来,顶尖架构师创造时代。

jQuery 的设计目的是,让前端工程师的工作更简单更轻松,但它并不适合所有的前端工程师,假如你的目标是成为优秀架构师、顶尖架构师的话,你在jQuery里也看不清未来。

9. jquery的源码看过吗能不能简单概况一下它的实现原理

原理就是对常用操作的封装,顺便解决了兼容性问题

10. jQuery 源代码看不懂,怎么办。。有没有解释jQuery 源代码的书籍

要不要阅读别人代码?
要。
阅读别人代码干什么?
提高自己的代码质量。
试图通过阅读别人代码找出代码的逻辑?
错误。
试图通过阅读别人代码找出想要实现自己的逻辑的代码?
正确,只有遵循了这个原则,才能实现物为我所用。
毫无目的去看别人代码 不晕才怪呢。

阅读全文

与jquery源码分析aaron相关的资料

热点内容
linux软raid性能 浏览:366
贴片机编程软件下载 浏览:358
mooc大学乐学python答案 浏览:408
怎么投诉途虎app 浏览:37
安卓重力感应怎么关 浏览:720
我的世界ios怎么建服务器地址 浏览:759
服务器端口ip都是什么意思 浏览:262
华为主题软件app怎么下 浏览:840
我们的图片能够收藏加密吗 浏览:979
mysql空值命令 浏览:213
python整点秒杀 浏览:882
怎么样互传app 浏览:293
python分布式抓包 浏览:36
轻量级php论坛 浏览:342
如何查看应用存储在哪个文件夹 浏览:436
app开发项目范围怎么写 浏览:76
androidjms 浏览:843
弹珠连贯解压 浏览:243
程序员的网课 浏览:904
广东加密狗防拷贝公司 浏览:450