JQuery源码解析–extend篇
来源:互联网 发布:发票作废 上传数据 编辑:程序博客网 时间:2024/06/08 17:59
JQuery源码解析–extend篇
@前端攻城狮LaoXu
目录
- JQuery源码解析extend篇
- 流程分析
- JQuery源码部分
- extend分析
- extend传递一个参数
- boolean类型
- string类型
- number类型
- Object类型
- Function类型
- Array类型
- extend传递两个参数
- 决定性的参数arguments0
- extend传递多个参数
- 特殊情况的说明针对Boolean
- extend传递一个参数
- extend特点
流程分析
JQuery源码部分
说明:JQuery版本–v1.11.3 jQuery JavaScript Library v1.11.3
jQuery.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
时为浅拷贝,只针对于第二个对象参数和返回值得对比
- JQuery源码解析–extend篇
- jQuery.extend()源码解析
- jQuery源码解析之jQuery.extend(),jQuery.fn.extend()
- jquery源码-jquery.extend()
- jQuery源码-jQuery.extend
- jquery.extend源码分析
- jQuery源码解析--插件接口设计($.extend)
- jQuery.extend函数解析
- jquery之extend解析
- jquery extend 解析
- jQuery源码分析-extend函数
- jQuery.extend函数源码详解
- jQuery中extend()源码分析
- jQuery.extend()方法和jQuery.fn.extend()方法源码分析
- jQuery源码分析10: jQuery.extend
- jquery源码阅读之jquery.extend
- jQuery 源码学习(一)jQuery.extend()
- jquery源码分析之扩展函数 extend, $.extend
- 关于Java工程的资源目录
- 研究生手册(二)
- CodeForces 699C
- 开发一个井字游戏
- 面向对象开发公众号,php代码封装类,函数
- JQuery源码解析–extend篇
- 给定一个没有重复数的数组。建立一棵最大树
- pandas之get_dummies
- 资源帖
- VS2010中添加lib库引用
- Java
- 设计原则(二)
- 建议掌握的视频站seo优化教程
- CKG1156-Java Spring 技术栈构建前后台团购网站