jquery-extend源码分析

PS:此次分析基于2.0以上版本;jquery

jquery的extend你们都不陌生,也是jquery的重要接口,写过jquery组件的人都用过extend吧!ajax

先说两个$.extend()和$.fn.extend();json

当只写一个对象自变量的时候,是Jquery中扩展插件的形式;$.extend() ->$.ajax;数组

而$.fn.extend是扩展Jquery实例方法; $.fn.extend ->$().方法;函数

接下来看下extend的源码,首先在jquery中定义了一些变量:oop

var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;   //是不是深拷贝this

将目标定为第一个参数,正常状况下目标元素是个对象,固然后面jquery会作处理;prototype

if ( typeof target === "boolean" ) { 
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}插件

在第一个判断中,会判断目标对象是不是布尔值,若是是,说明是深拷贝,将目标元素设为第二个参数;对象

if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}

这个时候已经肯定目标对象是对象了,如今判断目标对象不是对象或者函数的时候,将目标对象转换为对象;

if ( length === i ) {
target = this;
--i;
}

接下来的这个判断是判断是否是插件形式,若是只写一个对象,把这个对象扩展到jquery源码上,只要判断length和i是否相等。若是相等的活,把target设为this,this可能为两种状况,$或者$.prototype.

for ( ; i < length; i++ ) { //多个对象的状况
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];

// Prevent never-ending loop
if ( target === copy ) { 
continue;
}

// Recurse if we're merging plain objects or arrays
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 : {};
}

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) { 
target[ name ] = copy;
}
}
}
}

这个for循环是处理对个对象的状况,若是有多个对象,多个对象都要扩展到第一个对象上面。for循环中的if以下

if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];

首先判断参数是否有值,而后把各类赋值。接下来以下:

if ( target === copy ) { 
continue;
}

这个if是判断是防止循环引用的,如:

$.extend(x,{name : x}),若是不作上面那个if判断,若是写成这样会形成循环引用。

接下来会开始判断深度拷贝仍是浅拷贝

f ( 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 : {};
}

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}

首先经过deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) )判断;deep -> 深浅拷贝  copy ->是不是对象或者数组

不知足以上条件就是浅拷贝。

if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}

这个判断是拷贝数组和json不一样状况的不一样处理。

若是src只写src={}/ src=[];不写src && jQuery.isPlainObject(src) ? src : {}/src : [];

这样写若是在多个对象继承的时候,若是对象a和对象b有相同名字的属性,就会把a原有的属性给覆盖,经过jquery的处理,就不会覆盖之前的属性。

target[ name ] = jQuery.extend( deep, clone, copy );

在深拷贝中其实就是利用递归,针对不一样状况,分别处理。

相关文章
相关标签/搜索