源码解析

在解析代码之前,首先要了解extend函数要解决什么问题,以及传入不同的参数,会达到怎样的效果。extend函数内部处理传入的不同参数,返回处理后的对象。

extend函数用来扩展对象,增加属性和方法。

传入的参数有以下形式:

详细参见:解析jQuery中extend方法--用法《一》

  1. 可以传入N多个参数,将src1,src2..srcN的每一项合并到dest中
	extend(dest,src1,src2...srcN);
  1. 只传入一个对象时,$.extend(),给jQuery扩展静态方法;$.fn.extend(),给jQuery扩展实例方法。
	extend(dest);
  1. 第一个参数为布尔值,为true完成深层拷贝,为false完成浅拷贝。
	extend(Boolean,src1,src2);

了解到extend传入的参数,那么分析源码就很清晰:

jQuery.extend = jQuery.fn.extend = function() {
/*
传入的对象分为扩展对象和被扩展对象
*/
var options, name, src, copy, copyIsArray, clone, //
target = arguments[0] || {}, //被扩展的对象
i = 1, //设置扩展对象的起始值,默认从第二项开始
length = arguments.length, //传递参数的个数,以便下面循环扩展对象使用
deep = false; //默认浅复制 /*
处理深层拷贝或浅拷贝情况
extend(Boolean,src1,src2..srcN);
*/
if ( typeof target === "boolean" ) { deep = target; //将deep设为target,此时target为传进来的Boolean值,true or false; target = arguments[ i ] || {}; //重新设置被扩展对象,为参数的第二项 i++; //重设扩展对象的起始值,从第三项开始
} /*
被扩展的不是对象或函数,可能是String,Number或其他;
extend("",src1,src2...srcN);
*/ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {}; //重新设置target的值为空对象
} /*
当只传入一个对象
extend(src1);
将target设为jQuery对象或者jQuery.prototype,来扩展jQuery静态属性方法或是实例属性方法
$.extend(src1); //扩展jQuery对象
$.fn.extend(src1) //扩展jQuery.prototype
*/
if ( i === length ) {
target = this;
i--; //重设扩展对象起始值,从第0个开始
} /*
被扩展对象和扩展对象所有情况处理完毕,开始循环进行拷贝
对从i开始的多个参数进行遍历
*/ for ( ; i < length; i++ ) { if ( (options = arguments[ i ]) != null ) { //只处理有定义扩展对象
//扩展基本对象
for ( name in options ) { //循环每一项扩展对象
src = target[ name ];
copy = options[ name ]; // 防止循环引用,window === window.window.window
if ( target === copy ) {
continue;
} /*
对象或数组做深拷贝
deep:判断是否要深拷贝
copy:保证copy存在
jQuery.isPlainObject:判断copy是否是一个纯粹的对象,通过{} 或 new Object 创建
jQuery.isArray:判断是否为数组
*/
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
//为数组
if ( copyIsArray ) {
copyIsArray = false; //设为false,以便下次再重新判断是否为数组
clone = src && jQuery.isArray(src) ? src : []; //设置clone为一个数组 } else {
clone = src && jQuery.isPlainObject(src) ? src : {}; //设置clone为一个对象
} //递归深度拷贝
target[ name ] = jQuery.extend( deep, clone, copy ); //过滤未定义的值
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
} //返回修改后的对象
return target;
};

内部源码不是很复杂,主要是处理传入的不同参数。这个函数的实现,真正要理解的其实是递归。

递归

递归,就是在运行的过程中调用自己。

从简单的递归入手,以阶乘为例:

	function recursion(num){
if( num < 1 ) { //满足条件,终止递归调用
return 1;
};
return recursion( num - 1 ) * num;
};
recursion(6); //720

简单的递归运算,说说它的原理。

递归运算过程跟栈的数据结构很相似,遵循先进后出的原则。比如阶乘这个例子:

自上而下不断调用自身,直到不满足条件为止						自下而上返回数据进行运算,得到最终值		

1) recursion(num) 		-------> 	recursion(6) 		=== 	720
| | ↑
| | -----------
↓ ↓ |
2) recursion(num - 1) * num -------> recursion(6 - 1) * 6 === 120 * 6 = 720
| | ↑
| | ----------
↓ ↓ |
3) recursion(num - 1) * num -------> recursion(5 - 1) * 5 === 24 * 5 = 120
| | ↑
| | --------
↓ ↓ |
4) recursion(num - 1) * num -------> recursion(4 - 1) * 4 === 6 * 4 = 24
| | ↑
| | --------
↓ ↓ |
5) recursion(num - 1) * num -------> recursion(3 - 1) * 3 === 2 * 3 = 6
| | ↑
| | --------
↓ ↓ |
6) recursion(num - 1) * num -------> recursion(2 - 1) * 2 === 1 * 2 = 2
| | ↑
| | --------
↓ ↓ |
7) recursion(num) -------> recursion(1) === 1
(num < 1 返回值为 1) (结束调用自身,返回数值1)

一上来先调用recursion(num),也就是1),不满足递归停止的条件,内部调用自身,继续进行2),3),4),5),6)步,当到7)步时,num<1,返回值1,停止调用自身,然后依次从6),5),4),3),2),1)步,根据上一次调用的返回值参与运算,得到最终结果。

也可以这样理解,定义一个数组,每调用一次自身就向数组里push一个自身的函数,直到满足条件停止调用自身为止,然后从数组的最后一项依次向前一个函数传递返回值,直到调用到第一个函数为止。

理解了以上递归的过程,就不难理解深层拷贝。

递归调用把我搞的七荤八素,一直不能想象和理解它是怎样的一个运算过程。为此我已郁闷很久,在某天与一位大牛的闲聊中无意提起递归,在大牛的讲解举例,琢磨回味一番后,终于算是理解了递归是怎么一回事。不知准不准确,但至少再看到递归调用时,脑子立马清晰呈现递归调用是怎么一回事。

希望对大家有帮助,望批评斧正,共同学习!

解析jQuery中extend方法--源码解析以及递归的过程《二》的更多相关文章

  1. 解析jQuery中extend方法--用法《一》

    extend方法在jQuery中是一个很重要的方法,jQuey内部用它来扩展属性方法.常用语jQuery插件开发. jQuery提供了两个方法,$.extend和$.fn.extend,两个方法内部实 ...

  2. jQuery.extend()方法和jQuery.fn.extend()方法源码分析

    这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子: html代码如下: <!doctype html> ...

  3. Scala 深入浅出实战经典 第65讲:Scala中隐式转换内幕揭秘、最佳实践及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  5. Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  7. Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  8. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

  9. Spring Security 解析(七) —— Spring Security Oauth2 源码解析

    Spring Security 解析(七) -- Spring Security Oauth2 源码解析   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...

随机推荐

  1. android studio 更新失败解决办法

    在andriod studio目录下找到studio.exe.vmoptions这个文件,用记事本打开,在后面加上 -Djava.net.preferIPv4Stack=true -Didea.upd ...

  2. leetcode-004 insertion sort list

    package leetcode; class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } ...

  3. 部分网站允许空白referer的防盗链图片的js破解代码

    Reference: http://www.114390.com/article/27125.htm Javascript源码: 复制代码代码如下: function showImg( url ) { ...

  4. 学习tabhost 实现微博的主界面

    2014-05-27 吴文付 微博的主界面还是很漂亮的,我们这里来熟悉下tabhost的使用, 网上资料很多,主要参考了:http://blog.csdn.net/shulianghan/articl ...

  5. chkdsk

    通过 Microsoft 的相关帮助就可以明白,例如对D盘进行操作,则: 示例1:chkdsk /? 显示帮助信息. 示例2:chkdsk d: 检查D盘的磁盘状态,报告磁盘错误. 示例3:chkds ...

  6. 完美解决夏天电脑cpu发烫问题

    最近有朋友跟我反馈,说苹果电脑虽然好用,但是一直有一个问题困扰着他,就是电脑散热的问题.每到夏天的时候,电脑运转之后就会发烫,用的特别的不舒服. 相信用电脑的都会有这样的感受吧,更加相信你们都用过以下 ...

  7. 开篇 Android系统的体系结构

    1.APPLICATIONS (应用程序层) 2.APPLICATION FRAMEWORK(应用程序框架)  android应用程序提供了大量应用程序供开发者使用,当我看开发android应用程序时 ...

  8. xhtmlrenderer渲染pdf,中文换行

    在实际开发中,发现在table中显示中文,渲染出来的pdf,中文内容不自动换行.经过搜索发现了一种解决方案,如下: 重写Breaker,修改right计算方式 /* * Breaker.java * ...

  9. SVG的path的使用

    SVG的path的使用: 参考:http://justcoding.iteye.com/blog/2226354 <%@ page language="java" conte ...

  10. netcat工具的使用

    用途:网络管理工具. 可以读,写TCP或UDP 网络连接.简写为:nc 常见参数: -h  帮助信息 -l 坚挺模式 -n 指定IP地址 -p 指定端口号 -v 详细输出 1 客户端:很容易建立一个客 ...