深入理解jquery中extend的实现

2020-05-27 17:58:03易采站长站整理

// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}

// 从第i个参数开始
for ( ; i < length; i++ ) {
// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
// 因此可以用null来同时过滤掉null和undefind
// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {

// 使用for~in获取该参数中所有的字段
// Extend the base object
for ( name in options ) {
src = target[ name ]; // 目标参数中name字段的值
copy = options[ name ]; // 当前参数中name字段的值

// 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值
// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
// Prevent never-ending loop
if ( target === copy ) {
continue;
}

// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 若当前参数中name字段的值为Array类型
// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

} else {
// 若原对象存在,则直接进行使用,而不是创建
clone = src && jQuery.isPlainObject(src) ? src : {};
}

// 递归处理,此处为2.2
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

// deep为false,则表示浅度拷贝,直接进行赋值
// 若copy是简单的类型且存在值,则直接进行赋值
// Don't bring in undefined values
} else if ( copy !== undefined ) {
// 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
target[ name ] = copy;
}
}
}
}

// 返回修改后的目标参数
// Return the modified object
return target;
};

源码分析完了,下面我们来讲解下源码中存在的几个难点和重点。

2.1 若参数中字段的值就是目标参数,停止赋值

在源码中进行了一下这样的判断:


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

为什么要有这样的判断,我们来看一个简单的例子,如果没有这个判断会怎么样: