现在看到jQuery
的227行,本篇读jQ的继承方法jQuery.extend()
。
官方作用解释是将一个或多个对象合并到目标对象中。
jQuery.extend( [deep ], target, object1 [, objectN ] )
:
deep
是布尔类型,如为true
,则执行深拷贝,即合并成为递归;target
是一个对象扩展,如果附加的对象被传递给这个方法将那么它将接收新的属性,如果它是唯一的参数将扩展jQuery的命名空间;object1
到objectN
同样作为对象,包含额外的属性合并到第一个参数。看下源码实现:
jQuery.extend = jQuery.fn.extend = function(){
//方法体...
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[ i ] || {};
i++;
}
if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
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 = Array.isArray( copy ) ) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && Array.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;
}
在jQuery
对象上添加extend属性,并且在jQuery.fn
上面也添加同样的extend
属性,还记得前面jQuery.fn = jQuery.prototype
不?jQuery
对象的fn
属性指针就指向jQuery
对象的原型,并且因为对象都是引用类型的,所以上例代码的操作意思就是:在jQuery
对象和它的原型对象上都添加extend
方法,该方法最后返回的是一个合并处理后的对象。
在jQuery
对象上绑定的extend()
和jQuery.fn
上绑定的extend()
方法其实是不同的,前者是类方法,是静态方法,调用方法写作$.extend()
;后者是实例方法,是成员方法,调用方法写作$(selector).extend()
。
extend()
方法中,首先定义了一些初始变量:
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
deep
作为布尔类型值表明是否深度拷贝对象,如为true
,且多个对象的某个同名属性也都是对象,则该"属性对象"的属性也将进行合并。target
就是最后准备返回的一个对象,定义时被赋予初始值对象,arguments[ 0 ] || {}
指如参数数组有值则返回参数数组索引为0的值,否则就是返回一个空对象给target
变量。
接下来是首个传参为布尔值进行处理,如true
则执行深拷贝,并将第二个参数赋值给target
对象:
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[ i ] || {};
i++;
}
当传入extend
方法的第一个参数为布尔类型时,如存在传入第二个参数,则获取当前索引加1的参数并赋值给target
,或者参数取值为假时,直接将||
符号右边的空对象{}
赋值给target
。
然后就是对target
值为非对象类型的情况进行处理:
if(typeof target !== 'object' && !isFunction(target)){
target = {};
}
当target
为string
类型或其他基本类型值或者是函数类型时,将target
值直接用空对象赋值。
处理完不合适的参数类型,接下来就要进行方法本身逻辑了,先来个简单的:
if(i === length){
target = this;
i--;
}
当i === length
为真的情况,表示传参只传了一个对象参数,则方法return
出来的target
就是jQuery
这个类对象本身。通过这种方式,可以为全局对象jQuery
扩展新的方法:
$.extend({ //添加新的类方法
sum: function(a, b){
return a + b;
}
})
// 或者
$.fn.extend({ //添加新的实例方法
diff: function(c, d){
return c - d;
}
})
这种功能在使用jQuery
开发新的插件时,就非常有用了。
接下来就是extend
方法的主要逻辑块了,其只处理值为非null
和非undefined
的情况,具体代码解释下看注释:
for ( ; i < length; i++ ) {
// 只处理非null非undefined值
// tips: 这个有个小技巧,undefined == null 值为true; 但undefined === null值为false。所以通过 !=null 这个操作,就可以直接屏蔽掉 null和undefined两种情况了。
// 通过for循环将每个传入的参数赋值给变量 options
if ( ( options = arguments[ i ] ) != null ) {
// 扩展基对象
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// 防止死循环操作,如果全等,直接跳出
if ( target === copy ) {
continue;
}
// 当合并纯对象或数组时进行递归操作。所谓纯对象,指的就是普通的键值对形式构成的对象
// 当deep为true意为执行深拷贝,且copy对象为纯对象 或 copy对象为数组 Array.isArray()用于确定传递值是否为数组,返回一个布尔值
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
if ( copyIsArray ) { //如果为数组,则将数组赋值给clone变量,否则就将对象赋值给clone变量
copyIsArray = false;
clone = src && Array.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// 这里是确保不影响原对象,只是克隆它们
target[ name ] = jQuery.extend( deep, clone, copy );
// 确保不会操作到undefined值
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
以上就是jQuery
对象和jQuery.fn
即原型对象上添加extend()
方法的代码解释,再复习下:jQuery
对象和其原型上都具有extend()
方法,区别在于一个是类方法,一个是成员方法,在使用场景上请注意。
喜欢本文请扫下方二维码,关注微信公众号: 前端小二,查看更多我写的文章哦,多谢支持。