jQuery.extend函数源码详解

测试代码1:

var x = { name:"CodePlayer", age: 20 };
var y = { age: 18 };
var z = { site: "www.365mini.com", age: 21  };
var obj = $.extend( x, y, z );
这种调用下,target就是arguments[0]也就是x对象
isArray函数源码分析:

isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
测试代码2:

$(document).ready(function(){
var x = { name:"CodePlayer", students:[1,2,3] };
var y = { name: "xxx",students:[3,4,5]};
alert(jQuery.extend(true,x,y).students);//返回3,4,5,因为两个students的键名是一样的都是数组下标,所以会覆盖!
//迭代x,y时候都会迭代出来students集合,然后y的studenets就是isArray返回true
//这时候target就是x对象,
});
测试代码3:

 var x = [1,2,3];
var y = [3,4,5];
alert(jQuery.extend(true,x,y));//输出3,4,5
因为上面的for..in循环每次迭代出来的name是0,1,2也就是数组的下标,所以会后面的不断覆盖前面的!当对象中出现了数组属性等时候就会是这种情况和测试代码2是一样的道理!
测试代码4:

var x = {name:"qinliang",age:12,length:2}
var y = {name:"xxx",age:23,sex:"female",length:3}
var result=jQuery.extend(true,x,y);
for(var name in result)
{
 alert(name+"->"+result[name]);//会打印sex
}
它是以options也就是第二个y迭代的,x作为target,所以当把name,age,length迭代完了以后还要跌倒y的sex属性。src=target[name],copy=options[name],name是sex,这时候copy就不是undefined,而是female,这时候直接封装到target上面就可以了!
测试代码5:

var x = [1,2,3]
var y = [7,8,9,10]
var result=jQuery.extend(true,x,y);
for(var name in result)
{
 alert(name+"->"+result[name]);//输出7.8.9.10因为for in迭代出来的name是0,1,2,3,前面三个下标被覆盖,后面一个下标直接添加到target中!
}
测试代码6:

 var x = { 
sayHi: function(){
   alert("这是新增的测试方法");
}
};
// 只有一个参数,则表示省略target参数,target参数默认为jQuery对象本身
var obj = $.extend( x );
alert( obj === $ ); // true
$.sayHi(); // 这是新增的测试方法
//target就是作为基对象用来扩展属性和方法的,如果没有第一个boolean参数,那么就是第一个参数否则为第二个参数
var x = { name:"CodePlayer", age: 20 };
var y = { age: 18 };
var z = { site: "www.365mini.com", age: 21  };
var obj = $.extend( x, y, z );
alert( obj === x ); // true
});

测试代码7:

如果target不是一个对象,同时target也不是一个函数,那么把target设为空对象{}
alert($.extend(1,2));第一个不是boolean,target就是1,但是1不是object也就是typeof 1不是[object Object]
alert(typeof 1);是number

jQuery源码分析:

jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
//获取第一个参数
target = arguments[0] || {},
i = 1,
//获取参数的个数
length = arguments.length,
//默认是浅复制
deep = false;
// Handle a deep copy situation
//如果第一个参数是boolean类型,那么把该参数赋值给局部变量deep
if ( typeof target === "boolean" ) {
deep = target;
// skip the boolean and the target
//target默认保存的是第一个参数,如果第一个参数是boolean,那么直接保存为第二个参数,只是为了匹配调用方式一和调用方式二的!
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
//如果只有一个参数,这时候i就是1,length也就是1,那么把target设置为调用者,也就是jQuery对象本身!同时把i递减为0
//alert($.extend(1));
if ( i === length ) {
target = this;//这里this就是jQuery,因为是jQuery调用的!
i--;
}
//循环传递进来的参数集合
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
//获取逐个参数
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
//把每一个object类型参数的属性迭代出来
for ( name in options ) {
src = target[ name ];
//获取当前迭代的options的同名属性值,因为options是一直变化迭代出来的对象,但是target就要返回的对象,所以他是“静态的”
copy = options[ name ];
// Prevent never-ending loop
//如果原有属性和现在迭代出来的属性一样,如上面例子中x和y,z都有age属性!如果相同那么继续下面的循环,例如如果age都是等于18就继续下一次循环!
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
//copy是当前迭代出来的属性值,deep是否表示深度克隆,如果当前迭代出来的还是{}或者new Object构造的对象或者是Array类型或者类数组类型
//那么表示要深度克隆
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) )
//如果是类数组对象,[1,2,3]
if ( copyIsArray ) {
copyIsArray = false;
//如果target原来的name属性是Array,那么clone就是原来的Array
//下面调用target[ name ] = jQuery.extend( deep, clone, copy );
//也就是说会把clone作为target继续递归调用,把递归调用的结果设置为刚才的students的集合
//所以后面的copy还是会覆盖前面的clone
clone = src && jQuery.isArray(src) ? src : [];
} else {
//不是类数组对象
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
//让clone作为target,把copy上面的属性全部克隆到clone上面去!也就是全部克隆到clone上去
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {//假如deep是false,上面的if就不会满足,那么就是浅层次克隆,那么结果就是后面的覆盖掉前面的属性
//因为这种直接赋值就会导致覆盖,给了target对象相同的属性
target[ name ] = copy;
}
 }}
// Return the modified object
return target;
};

总结:

(1)第一个参数表示是否深度克隆,如果是深度克隆就会把数组或者对象拆分出属性,然后遍历属性而不是直接覆盖!

(2)参数deep的默认值为false,你可以为该参数明确指定true值,但不能明确指定false值。简而言之,第一个参数不能为false值。如果参数为nullundefined,则该参数将被忽略。

(3)如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。只有一个参数那么就会满足i===length,所以target就是this了!这时候i为0,表示用this继承第一个参数属性!

(4)底层的深度克隆的案例就是上面的测试代码2.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值