您的位置:首页 > Web前端 > JQuery

jQuery源码解读2:.extend()函数

2017-10-11 00:00 507 查看

一、不防从我们所有认识这个函数的功能入手

1. 这个函数把系列对象合并后返回一个新对象

2. 合并有两种方式,规定在第一个参数上指明,true为深度,false为浅度。

第一个参数在源码中被确定用来表示是否深浅合并:如代码段:

target = arguments[ 0 ] || {},


二、逐行解释源码

//.extend函数是jQuery()对象的方法也是jQuery静态工具函数
jQuery.extend = jQuery.fn.extend = function()
{
var options, name, src, copy, copyIsArray, clone,
//默认如果不指定合并类型:深度或者否,默认的目标是第一个参数(target定1)
target = arguments[ 0 ] || {},
i = 1,
//巧用不定参,可以让这个函数的功能多样化
length = arguments.length,
//默认为false,默认不深度递归合并
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
//上面把 i = 1 就是要跳过第一参数(当检测到第一个参数为布尔型时)
//如果存在指定合并类型,那先这个目标对象就被改成下个参数(target改1)
target = arguments[ i ] || {};
//如果存在合并类型且已经确定第一参数为目标对象的话,i++就是开始表明现在可以开始从i++开始找源对象了!
i++;
}
// Handle case when target is a string or something (possible in deep copy)
//如果传进来的目标不是一个对象而是非对象的其他数据类型(null 、字符串、undefined等)
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};(target改2)
}

// Extend jQuery itself if only one argument is passed
//如果传进来就只有一个参数或者两个参数(其中一个是合并类型布尔型),也就是说传进来的参数只有目标对象无源对象,
//那就修改目标对象为this(虽然上面(target定1)有默认表示第一个参数是目标对象),把第一个对象参数当做源对象。
if ( i === length ) {
target = this;//(target改3)
//因为上面误以为有两个参数,且第一参数是合并类型的布尔型,第二个参数是目标对象,上面i++。
//既然是误以为造成的i++,实际只有一个参数就得还原回来!
i--;
}
for ( ; i < length; i++ ) {
//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
//当前的源对象复制属性copy是普通JavaScript对象或数组,则递归合并
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {

if ( copyIsArray ) {
copyIsArray = false;
//如果原始值src不是数组,则修正为空数组
clone = src && Array.isArray( src ) ? src : [];

} else {
//如果原始值src不是普通JavaScript对象,则修正为空对象{}。
clone = src && jQuery.isPlainObject( src ) ? src : {};
}

// Never move original objects, clone them
// 递归调用extend方法,继续进行深度遍历
target[ name ] = jQuery.extend( deep, clone, copy );  //递归
//注意这里的递归得到的一个完整的对象赋给目标对象的[name]属性。而不是把递归中的属性给到目标对象属性

// Don't bring in undefined values
//如果不是深度合并
} else if ( copy !== undefined ) {
target[ name ] = copy;
//如果不是深度合并,碰到源对象的属性为一个完整的对象,也不去递归了!
}
}
}
}

// Return the modified object
return target;
};


三、注意深度递归合并与非深度合并直接的区别:

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

举个例子就能比较直观的看到问题

//默认的非深度递归
jQuery.extend({ name: “John”, location: { city: “Boston” } },
{ last: “Resig”, location: { state: “MA” } }
);
// 结果:  => { name: “John”, last: “Resig”, location: { state: “MA” } }

//深度递归
jQuery.extend( true,
{ name: “John”, location: { city: “Boston” } },
{ last: “Resig”, location: { state: “MA” } }
);
// 结果 => { name: “John”, last: “Resig”, location: { city: “Boston”, state: “MA” } }


四、学到的技术点

1. 采用“不定实参”arguments

2.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  .extend jQuery源码