JQuery源码解析–extend篇
2017-11-26 09:42
120 查看
JQuery源码解析–extend篇
@前端攻城狮LaoXu目录
JQuery源码解析extend篇
流程分析
JQuery源码部分
extend分析
extend传递一个参数
boolean类型
string类型
number类型
Object类型
Function类型
Array类型
extend传递两个参数
决定性的参数arguments0
extend传递多个参数
特殊情况的说明针对Boolean
extend特点
流程分析
JQuery源码部分
说明:JQuery版本–v1.11.3 jQuery JavaScript Library v1.11.3jQuery.extend = jQuery.fn.extend:
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和target值(不要去管deep的Boolean类型) target = arguments[ i ] || {}; i++; } // 处理当target是一个字符串或者是其他的值时(也可能需要深拷贝处理) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 如果只传递一个参数时,只是去扩展JQuery本身(为JQuery添加插件) if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // 仅处理 非空/未定义 的值 if ( (options = arguments[ i ]) != null ) { // 扩展基本(目标/源)对象 for ( 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 ); // 不要去引入未定义的值 } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // 返回修改后的对象 return target; };
extend分析
在分析代码之前先整理一下内部的变量值,变量值的具体说明如下:var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {},// traget为传递的第一个参数或者为{} i = 1,// i为数值1 length = arguments.length,// length 长度是传递的参数的长度 deep = false;// deep表示是否深拷贝
extend传递一个参数
boolean类型
当第一个参数为boolean类型值为true时:
当第一个参数为
true时,当前的变量
target的值是传递过来的第一个参数(第3行),也就是
boolean类型的值。在执行到 第9行
if ( typeof target === "boolean" )并进入到判断体内 ,在此内部会将
deep设置为
true。而
target变量会将传递的第二个参数设置进去,但是并没有去传递第二个参数,则会默认设置为
{},此时的
i会进行
++i的操作,
i
代码继续向下执行会来到 18行
if ( typeof target !== "object" && !jQuery.isFunction(target) )的判断,此时的target是一个
{},所以条件不成立,继续往下执行。
执行到 23行
if ( i === length )的判断时,此时的
i已经变成
2,而
length是传递的参数的长度(
1),同样条件也不成立。
代码继续向下执行到 28行
for ( ; i < length; i++ ),此时的
i是
2,而
length为
1,则
for循环内的判断条件不成立。
最后代码将执行到 63行
return target;,此时的
target为
{},因此将返回一个
{}回来。
当第一个参数为boolean类型值为
false时:
当传递的参数为
false的时候在 第3行
target = arguments[0] || {}时,target的值将为
{},只有 第18行
if ( typeof target !== "object" && !jQuery.isFunction(target) )和 第 23行
if ( i === length )条件成立执行完 18行
target变为
{},在执行 23行 循环体内的方法后target值变为
jQuery,
i执行
i--变为
0。
向下继续执行
for循环,因为
i为
0,
length为
1所以执行循环体中的方法。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
boolean类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
false时取出来
name的为
undefined),当
name为
undefined时直接跳出
for循环执行一次循环。
最后执行完循环体后返回
target(jQuery)。
string类型
当第一个参数为string类型时:当第一个参数为
string时,当前的变量
target的值是传递过来的第一个参数(第3行),也就是
string类型的值。在执行到 第9行
if ( typeof target === "boolean" )时,条件并不成立,继续往下执行。
继续向下执行来到 第18行
if ( typeof target !== "object" && !jQuery.isFunction(target) ),此时的
target是
string类型的参数,条件成立,进入到条件体并将
target设置为
{}。
代码继续向下执行将来到 第23行
if ( i === length ),此时的
i为
1,
length同样也是
1,所以条件成立,执行条件体内的代码,此时的
target变成
this(jQuery),
i执行
i--的操作变为
0。
当执行到 第28行
for ( ; i < length; i++ ),此时的i为0,length为1,循环体内的条件成立,代码进入到循环体内。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
string类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
string时取出来
name的为下标值)在执行 第33行
src = target[ name ];和 第34行
copy = options[ name ];,
src为
undefined(
src此时是去取
this(jQuery)中的值),
copy为每次循环后的参数。
当代码执行到 第42行
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) )时,
deep为
false,
copy为每次循环取出来的参数,而
copyIsArray为
false条件不成立,去执行
else if中的方法,此时
copy有值,所以进入到循环体内,并将
copy中的值赋值给
target[name]中去 (当为
string时,
name为下标值)。
最后执行完循环体后返回
target(jQuery)。
number类型
当第一个参数为number类型:当传递的参数为
number的时候,只有 第18行
if ( typeof target !== "object" && !jQuery.isFunction(target) )和 第 23行
if ( i === length )条件成立执行完 18行
target变为
{},在执行 23行 循环体内的方法后target值变为
jQuery,
i执行
i--变为
0。
向下继续执行
for循环,因为
i为
0,
length为
1所以执行循环体中的方法。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
number类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
number时取出来
name的为
undefined),当
name为
undefined时直接跳出
for循环执行一次循环。
最后执行完循环体后返回
target(jQuery)。
Object类型
当传递的参数为Object类型:当传递的参数为
object时,只有第 23行
if ( i === length )条件成立,在执行 23行 循环体内的方法后target值变为
jQuery,
i执行
i--变为
0。
向下继续执行
for循环,因为
i为
0,
length为
1所以执行循环体中的方法。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
object类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
object时取出来
name的为对应的属性名),先找到对应
target上是否存在对应的属性值并赋值给
src,在去找
opations中对应的属性值并赋值给
copy。
当
deep不为
true时(表示深拷贝),为
target添加相应的属性
name并将
copy中的值(通过
name找到的属性值)赋值给
target[name]中去。
最后返回
target。
Function类型
当第一个参数为Function类型:当传递的参数为
Function的时候,只有第 23行
if ( i === length )条件成立,在执行 23行 循环体内的方法后target值变为
jQuery,
i执行
i--变为
0。
向下继续执行
for循环,因为
i为
0,
length为
1所以执行循环体中的方法。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
function类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
function时取出来
name的为
undefined),当
name为
undefined时直接跳出
for循环执行一次循环。
最后执行完循环体后返回
target(jQuery)。
Array类型
当第一个参数为Array类型时:当第一个参数为
array时,当前的变量
target的值是传递过来的第一个参数(第3行),也就是
string类型的值。在执行到 第9行
if ( typeof target === "boolean" )时,条件并不成立,继续往下执行。
继续向下执行来到 第18行
if ( typeof target !== "object" && !jQuery.isFunction(target) ),此时的
target是
array类型的参数,条件不成立。
代码继续向下执行将来到 第23行
if ( i === length ),此时的
i为
1,
length同样也是
1,所以条件成立,执行条件体内的代码,此时的
target变成
this(jQuery),
i执行
i--的操作变为
0。
当执行到 第28行
for ( ; i < length; i++ ),此时的i为0,length为1,循环体内的条件成立,代码进入到循环体内。
继续向下执行到 第30行
if ( (options = arguments[ i ]) != null ),取出第一个参数的值并赋值给
options(
array类型),并判断当前的第一个参数是否为空,此时第一个参数有值,进入到判断体内。使用
in关键字循环去取出
options中的值(
options为
array时取出来
name的为下标值)在执行 第33行
src = target[ name ];和 第34行
copy = options[ name ];,
src为
undefined(
src此时是去取
this(jQuery)中的值),
copy为每次循环后的参数。
当代码执行到 第42行
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) )时,
deep为
false,
copy为每次循环取出来的参数,而
copyIsArray为
false条件不成立,去执行
else if中的方法,此时
copy有值,所以进入到循环体内,并将
copy中的值赋值给
target[name]中去 (当为
array时,
name为下标值)。
最后执行完循环体后返回
target(jQuery)。
extend传递两个参数
说明:根据上面整理出来的结果基本上可以知道extend的内部执行流程,那么在传递两个参数时就无非有一些比较特殊的情况,接下来主要对几种特殊的情况加以说明,如果有不懂的地方可以通过浏览器的调试工具去查看代码的具体流程。
决定性的参数arguments[0]
arguments[0](传递的第一个参数)有着举足轻重的作用,它直接决定了返回的结果。
当
arguments[0]为
boolean类型的时候它将决定
target为
{}还是
this。并且会将第二个参数以对应的方式取出来存放到
target中去。
当
arguments[0]为
string/number类型的时候它都会返回一个
{}值,而
{}中的具体信息取决于第二个参数:
Boolean:返回空
{}对象
String: 返回
{}对象,并将
stirng字符串(分割)存入对象中去,属性就是对于的下标值,属性值就是取出来的值。
Number:返回空
{}对象
Object:返回
Object对象
Function: 返回空
{}对象
Array: 将
Array中的值一一取出并存入到
{}中去,属性就是对于的下标值,属性值就是取出来的值。
当
arguments[0]为
object类型的时候它将会去合并后面的对象或者参数,最后返回合并后的对象,具体如下:
Boolean:返回第一个(
arguments[0])对象
String:返回一个对象,并将
stirng字符串(分割)存入
arguments[0]的对象中去,属性就是对于的下标值,属性值就是取出来的值。
Number:返回第一个(
arguments[0])对象
Object:返回一个对象,并将
Object中的参数取出来并存入
arguments[0]的对象中去,属性就是对于的下标值,属性值就是取出来的值。
Array:返回一个
Array对象,将
Array中的值一一取出并存入到
Array数组中去,数组的下标就是对于的属性,数组中的值就是取出来的属性值。
Function:返回第一个(
arguments[0])对象
当
arguments[0]为
Array类型的时候它同样会去合并后面的对象或者参数,最后返回合并后的对象,但是在这里有一个非常特殊的情况,而个情况的关键点在于
in关键字是否获取的是下标值,如果是下标值,它将直接去覆盖
arguments[0]中
Array对于的下标值。
通过断点的方式是可以看出
arguments[0]决定这
target的值到底是一个普通的对象还是
jQuery对象,在使用
extend方法的时候需要额外的注意这种情况下的比较特殊性,通常情况下都是一个普通对象,只有在
boolean时是比较特殊的 *
extend传递多个参数
说明:相对于传递两个参数来说,传递多个参数的情况就比较简单明了,它直接返回一个合并后的对象(如果不是对象它将根据传递参数的类型进行in关键字的操作并转化成对象),很像JavaScript中的继承。当然它也有一些比较特殊的情况,这种情况适用于对象的继承,主要取决于第一个参数是否为true以及后面的参数是否为Object类型。(可以理解为拷贝类型的不同)特殊情况的说明(针对Boolean)
如果第一个参数在传递不同的Boolean值的时候,你会发现,如果你去修改原有的
Object对象时,再次输出
extend返回的参数有着很大的区别。这是为什么?
首先在进入到
extend的时候
target会去获取第一个参数,如果未获取到或者传递的为
false的时候它将变成
{}(一个新的对象),
如果在原有对象上进行拷贝赋值,此时就是一种浅拷贝,在我们去修改原有对象的同时,
extend的对象中的数据也同样发生着改变。如果
target被重新赋值一个新的对象
{}时,此时再去进行拷贝赋值就是一种深拷贝,如果再去修改原有的对象的同时是不会影响到
extend上对象的任何数据。(深拷贝和浅拷贝)
extend特点:
传递的参数都为Array类型的时候返回的一般为
Array类型,如果第一个参数是
false则返回的是
{}(普通对象)
当传递两个参数,第一个参数为
true时,则会为
jQuery对象上添加。
当传递多个对象的时候,如果第一个参数为
false,则为深拷贝,传递第一个参数为
true时为浅拷贝,只针对于第二个对象参数和返回值得对比
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- 从源码安装Mysql/Percona 5.5
- JavaScript演示排序算法
- 2015-2016网页设计趋势分析 Web Design of Trends
- jQuery Ajax 跨域调用
- 移动端的长按事件
- jquery教程靠边站,一分钱不花让你免费学会jquery
- JQuery+Strusts1.x无刷新登录
- $.ajax()方法详解
- jQuery ajax - ajax() 方法
- python--函数
- JQuery实例
- JavaScript 各种遍历方式详解
- 数组方法汇总
- java.util.concurrent 学习(一)
- Mootools 1.2教程 函数
- autoit InputBox 函数
- 文件遍历排序函数
- seajs学习教程之基础篇
- jQuery Html控件基本操作(日常收集整理)