jQuery源码研究分析学习笔记-jQuery.extend()、jQuery.fn.extend()(八)

时间:2022-12-02 20:51:56

jQuery.extend()、jQuery.fn.extend()主要用于编写插件和处理函数参数。
jQuery.extend(deep,target,objdect1 [,objectN])
jQuery.fn.extend(deep,target,objdect1 [,objectN])

参数deep是一个可选的布尔值,用于决定当前执行的是深复制还是浅复制,如果省略或者为false,就执行浅复制,如果第一个参数的属性本身 是一个对象或者数组,它会被第二个或后面的其他参数的同名属性完全覆盖,如果为true,表示进行深度合并,合并过程是递归的

参数target是目标对象,参数obect1和objdectN是源对象,包含了待合并的属性,如果提供了两个或多个对象,所有的源对象的属性将合并到目标对象;如果仅提供一个对象,jQuery或jQUery.fn将被当作目标对象,通过这种方式可以在jQuery或jQuery.fn上添加新的属性和方法。

jQuery.extend = jQuery.fn.extend = function() {

    //变量options:指向某个源对象
    //name: 表示某个源对象的某个属性名
    //变量src:表示目标对象的某个属性的原始值
    //变量copy:表示某个源对象的某个属性的值
    //变量copyIsArray:变量copy是否是数组
    //target:目标对象
    //i :表示源对象的起始下标
    // length:表示参数的个数,用于修正变量target
    //表量deep: 是否深度复制

    var options, name, src, copy, copyIsArray, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;

    // 判断第一个参数是否是布尔值
    if ( typeof target === "boolean" ) {

        //target是布尔值时候,修正第一个参数是deep,修改第二个删除是target,源对象从第三个元素开始
        deep = target;
        target = arguments[1] || {};
        // skip the boolean and the target
        i = 2;
    }

    // 如果target不是对象、不是函数,而是字符串或其他的基本类型,则统一替换成空对象{},因为在基本类型上设置非原生属性是无效的。
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
        target = {};
    }

    // 变量i表示源对象开始的下标,变量length表示参数个数,如果二者相等,则表示期望的源对象没有传入,则把jQuery或jQuery.fn作为目标对象,并且把源对象的开始下标减1,从而使得传入对象被当源对象。
    if ( length === i ) {
        target = this;
        --i;
    }
    //遍历对象属性
    for ( ; i < length; i++ ) {
        // 获取源对象和对源对象的判断
        if ( (options = arguments[ i ]) != null ) {
            // Extend the base object
            for ( name in options ) {
                src = target[ name ]; //原始值
                copy = options[ name ]; //复制值

                // 如果复制值和原始值相等,为了避免深度遍历时死循环,不会覆盖目标对象的同名属性
                if ( target === copy ) {
                    continue;
                }

                // 如果深度合并,且复制值copy是普通js对象或数组,则递归合并
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    //如果复制值copy是数组,
                    if ( copyIsArray ) {
                        copyIsArray = false;
                        //若原始值src不是数组,怎修正为空数组
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {

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

                    // 把复制值copy递归合并到原始值副本clone中,然后覆盖目标对象的同名属性
                    target[ name ] = jQuery.extend( deep, clone, copy );

                // 如果不是深度合并,并且复制值copy不是undefined,则直接覆盖目标对象的同名属性
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    // 返回合并后的值
    return target;
};

jQuery.isPlainObject(obj)方法是判断obj是否是“纯粹”的js对象,只有通过对象直接量{} 或new Object()创建的对象,才会返回true