最近尝试看看jQuery的源码。 版本 version = "1.11.1"

相对于看一本jQuery如何使用的书,看jQuery源码对它可以有更深层次的理解。jQuery中大量使用了正则表达式,对于全面提升JavaScript的能力也有很大帮助。由于考虑到了各种边界情况,以及对不同版本的浏览器的兼容等,jQuery整体代码都很严谨。

前言

jQuery源码中大量使用了&&和||  ,在JS中它们更像操作数选择器,它们的返回值是两个操作数的一个,而不是我们通常认为的返回true或者false。

     var a=3;var b='cc';var c=null;console.log(a||b);   //3console.log(a&&b);   //ccconsole.log(c||b);   //ccconsole.log(c&&b);   //null

&&和||会先对第一个操作数(也就是a||b中的a)做条件判断。

对于||来说如果条件判断结果为true,则返回第一个操作数的值,如果为false,则返回第二个操作数的值。

对于&&来说如果条件判断结果为true,则返回第二个操作数的值,如果为false,则返回第一个操作数的值。
JavaScript中的假值有(undefined、null、false、+0、-0、NaN、“”)

一 整体框架

去掉其他枝叶代码,先来看看jQuery的整体框架

(function( global, factory ) {if ( typeof module === "object" && typeof module.exports === "object" ) {module.exports = global.document ?factory( global, true ) :function( w ) {if ( !w.document ) {throw new Error( "jQuery requires a window with a document" );}return factory( w );};} else {factory( global );}}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {var jQuery = function( selector, context ) {return new jQuery.fn.init( selector, context );};jQuery.fn = jQuery.prototype = {//.........}var init = jQuery.fn.init = function( selector, context ) {//.........}init.prototype = jQuery.fn;if ( typeof noGlobal === strundefined ) {window.jQuery = window.$ = jQuery;}return jQuery;}));

可以看到jQuery整体是一个立即执行函数,JavaScript是函数作用域而非块作用域,因此其中定义的变量不会污染全局空间。if ( typeof module .......){} else  这部分代码用于检测代码运行环境,如果 module === "object"  说明是在CommonJS或者类似于CommonJS的环境中,使用 module.exports 向外暴露API。但是这样的环境中可能不存在window 对象,如果不存在window对象,就向外提供一个function,可以额外传递window对象作为参数。 在一般浏览器环境中则直接运行factory( global )运行。最后window.jQuery = window.$ = jQuery; 向外部暴露jQuery。

再来看看jQuery的初始化部分。也就是下面这部分。

var jQuery = function( selector, context ) {return new jQuery.fn.init( selector, context );};jQuery.fn = jQuery.prototype = {//.........}var init = jQuery.fn.init = function( selector, context ) {//.........}init.prototype = jQuery.fn;

我们很熟练的用类似于$('#cc') $('div')的方式创建jQuery对象,可以看到它返回了new jQuery.fn.init( selector, context ); 使用new实例化的一个对象,由于jQuery.prototype=jQuery.fn=jQuery.fn.init.prototype  因此挂载到jQuery实例上面的方法(定义在jQuery.prototype上的)也就挂载到了使用new jQuery.fn.init()创建的实例对象上。 jQuery.fn.init=jQuery.prototype .init 因此jQuery的实例也可以访问到init方法。

二  链式操作及pushStack

我们在使用jQuery是常常进行一些链式的操作比如这样:$('li').eq(1).css('background','red').end().length

$('li')获取到文档中所有的li, $('li').eq(1).css('background','red')取得第一个li,然后将它的背景色设置为红色,调用end()回到原来的状态,最后length获取文本中li的个数。

下面是一些常用的实例方法:get 、eq、end

jQuery.fn = jQuery.prototype = {get: function( num ) {return num != null ?( num < 0 ? this[ num + this.length ] : this[ num ] ) :slice.call( this );},pushStack: function( elems ) {var ret = jQuery.merge( this.constructor(), elems );ret.prevObject = this;ret.context = this.context;return ret;},first: function() {return this.eq( 0 );},last: function() {return this.eq( -1 );},eq: function( i ) {var len = this.length,j = +i + ( i < 0 ? len : 0 );return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );},end: function() {return this.prevObject || this.constructor(null);}
};

在理解代码之前先看看$('li')长什么样吧,就长下面这样,是一个类数组。包含了所有满足筛选条件的DOM对象,所以我们可以用$('li')[0]这样的方式获取到对应的DOM。

使用$('li').eq(0)可以获取到对应的jQuery对象,其中pushStack 在jQuery的源码中多次使用到。pushStack做了这些事:创建一个新的jQuery对象,将一个DOM数组的内容整合到里面,保存当前的环境和前一个jQuery对象。 因此在调用end的时候就可以由

prevObject属性找到前一个对象并返回。

三 extend扩展

使用jQuery.extend 可以用于扩展jQuery的静态方法。使用 jQuery.fn.extend 可用于扩展jQuery的实例方法。第一个参数是true的话代表深拷贝。如果没有提供目标对象的话则扩展自身,否则扩展目标对象。

jQuery.extend = jQuery.fn.extend = function() {var src, copyIsArray, copy, name, options, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;if ( typeof target === "boolean" ) {deep = target;// 跳过 boolean 和targettarget = arguments[ i ] || {};i++;}// 排除target是string等情况if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}// 扩展JQuery本身,如果只传递了一个参数if ( i === length ) {target = this;i--;}for ( ; i < length; i++ ) {//只处理非null/undefined 值if ( (options = arguments[ i ]) != null ) {// Extend the base objectfor ( name in options ) {src = target[ name ];copy = options[ name ];// 有环if ( target === copy ) {continue;}// 递归如果我们合并普通对象或数组if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) {copyIsArray = false;clone = src && jQuery.isArray(src) ? src : [];} else {clone = src && jQuery.isPlainObject(src) ? src : {};}target[ name ] = jQuery.extend( deep, clone, copy );// 排除掉 undefined values} else if ( copy !== undefined ) {target[ name ] = copy;}}}}// Return the modified objectreturn target;
};

     深拷贝指的是对象属性所引用的对象全部进行新建对象复制,以保证深复制的对象不包含任何原有对象及原对象的引用。在进行深拷贝时,如果子属性是数组或者对象,就进行递归调用直到全部拷贝完毕。

     jQuery.extend 和jQuery.fn.extend 使用同一个方法。如果要扩展自身的话,可以通过target = this区别出是对jQuery这个function进行扩展,还是对jQuery的一个实例进行扩展。

四 一些静态方法

jquery自身扩展的一些静态方法,比如jQuery.each 、 jQuery.map等都是常用的方法。这部分的源码都比较好理解,基本上了解这部分可以更加熟练地利用jQuery了。jQuery.merge函数用于合并两个数组内容到第一个数组。在jQuery内部也经常用到这个方法。

jQuery.extend({each: function( obj, callback, args ) {//....................},merge: function( first, second ) {var len = +second.length,j = 0,i = first.length;while ( j < len ) {first[ i++ ] = second[ j++ ];}// Support: IE<9// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)if ( len !== len ) {while ( second[j] !== undefined ) {first[ i++ ] = second[ j++ ];}}first.length = i;return first;},map: function( elems, callback, arg ) {//..........................}});

五 冲突检测

无论如何引入jQuery的js包都会在window中创建一个全局的jQuery和$。如果我们自己的代码中定义了同名的全局变量的话,就会引起冲突,可以通过jQuery.noConflict(true)来避免冲突。

var_jQuery = window.jQuery,_$ = window.$;jQuery.noConflict = function( deep ) {if ( window.$ === jQuery ) {window.$ = _$;}if ( deep && window.jQuery === jQuery ) {window.jQuery = _jQuery;}return jQuery;
};

在window.jQuery = window.$ = jQuery之前,使用变量_jQuery、_$ 存储当前环境的同名变量。在调用noConflict 之后,还原 window.$ = _$;

jQuery源码分析 整体框架部分及部分常用方法相关推荐

  1. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  2. [转] jQuery源码分析-如何做jQuery源码分析

    jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...

  3. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  4. jQuery源码分析-each函数

    本文部分截取自且行且思 jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 复制代码代码 /*! * jQuer ...

  5. 【OkHttp】OkHttp 源码分析 ( 网络框架封装 | OkHttp 4 迁移 | OkHttp 建造者模式 )

    OkHttp 系列文章目录 [OkHttp]OkHttp 简介 ( OkHttp 框架特性 | Http 版本简介 ) [OkHttp]Android 项目导入 OkHttp ( 配置依赖 | 配置 ...

  6. SpringMVC源码分析_框架原理图

                                                                                 SpringMVC源码分析_框架原理图     ...

  7. Activiti源码分析(框架、核心类。。。)

    Activiti源码分析(框架.核心类...) 目录 概 述 activiti源码分析(一)设计模式 总结: 相关工具如下: 分析: 小结: 参考资料和推荐阅读 LD is tigger foreve ...

  8. 【jQuery源码】整体架构

    jQuery源码可以精简为以下内容: 方框上面的代码根据Jq注释我们可以知道是对AMD规范的支持. jQuery整体上被包裹在一个匿名函数中,这个匿名函数再作为另一个匿名函数的参数被传入,形参fact ...

  9. Jquery源码分析-整体结构

    最近在学习Jquery的最新的源码,Jquery-3.3.1版本.网上有很多对jquery解析的文章.但是我还是要自己去尝试着看一篇jquery的源码.本系列博客用来记录其中的过程,并同大家分享.本次 ...

最新文章

  1. Linux网络编程:基于UDP的程序开发回顾篇
  2. Hibernate(1) 阻抗不匹配
  3. matlab、python使用小方法收集
  4. 台式计算机是32位还64位,怎么看电脑是32位还是64位
  5. bootstrap --- 鼠标停留提示事件
  6. Java反射————Method根据方法名称字符串调用方法
  7. Vue.js入学教程
  8. 一文带你看网络协议之因特网中的转发和编址! | 原力计划
  9. syslog(LOG_ERR, Error: errcode=%d, message=%s, errcode, errmsg);
  10. 金阳光测试算法专题——精选小算法汇总
  11. python斗鱼抽奖_Python实现抓取斗鱼实时弹幕
  12. 华人AI学者大盘点:清华培养了最多的高层次人才,韩家炜、吴恩达论文被引数“登顶”
  13. 冰川时代4中英台词全集
  14. vlan互通三种方式之二第二篇
  15. [kubernetes]-Pod无法通过 Service IP 访问自身
  16. 微信分享与支付开发详解
  17. 我的一点企业上云经验
  18. 邮箱服务RBL黑名单申诉
  19. Oracle数据库命名编码规范
  20. js获取唯一设备码_HTML5+下用js获取设备的唯一识别码和本地数据库的操作

热门文章

  1. SVN历史版本比较中文乱码
  2. iOS开发——高级技术通讯录功能的实现
  3. 如何设置WIN7自动登录(去除登录密码)
  4. 中文VS2008安装ASP.NET MVC框架解决方案
  5. 利用Sniffer进行路由环流量分析
  6. dataframe scala 修改值_【Spark学习笔记】 Scala DataFrame操作大全
  7. 关于操作 ASP.NET Web API的实例
  8. JS实现让页脚一直固定在页面底部
  9. ORA-09925: Unable to create audit trail file 在DBCA时
  10. 错误提示:ssh: Could not resolve hostname devsrv: Name or service not known