首页 > 代码库 > jQuery剥皮二 - extend

jQuery剥皮二 - extend

jquery1.4  jquery1.4下载

这里使用了 jQuery1.4,为什么使用 1.4 因为 1.4 很多特性没有添加分析起来相对容易。


extend 可以说是 jQuery 用的最多的函数之一了,除了核心的几个函数之外其他的几乎全部用 extend 进行原型或者静态函数的扩展。下面来看看 extend 如果完成这样的工作的吧

jQuery.extend = jQuery.fn.extend = function() {
	// copy reference to target object
	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;

	// Handle a deep copy situation
    // 深度拷贝
	if ( typeof target === "boolean" ) {
		deep = target;                            // 修正深度拷贝
		target = arguments[1] || {};              // 修正目标
		// skip the boolean and the target        // 如果是深度拷贝 修正循环(跳过第一个参数(0)和目标(1))
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
    // 确保目标元素是对象且不是函数,但可以是函数对象(new 函数)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
		target = {};
	}

	// extend jQuery itself if only one argument is passed
    // 当扩展的对象只有一个的时候,就视为扩展 jQuery
	if ( length === i ) {
		target = this;            // 修正 this 为jQuery
		--i;
	}
    // 遍历参数
	for ( ; i < length; i++ ) {
		// Only deal with non-null/undefined values
        // 遍历不是 null 的值(对象)
		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 object literal values or arrays
                // 深拷贝,且 copy 是对象或者数组
                /**
                * deep => true
                * copy == true
                * copy => 必须是绝对对象 或 copy 是一个数组
                * 
                */
				if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
                    /**
                    * 如果目标元素和要拷贝的元素有相同的 key 并且也是对象或者数组那么就返回目标对象的 key
                    * 否则创建一个对应的类型用于保存数据
                    */
					var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
						: jQuery.isArray(copy) ? [] : {};

					// Never move original objects, clone them
                    // 对子项进行拷贝
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don‘t bring in undefined values
                // 不是深拷贝
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

下面我列出一下 extend 的一些用法 手册描述

1、这种是最基本的用法

var t = $.extend({a:"123"}, {b:‘456‘});
console.log(t);
//Object {a: "123", b: "456"}

2、深度拷贝

var o1 = {
    txt: "123",
    a: {
        ‘a_text‘: ‘a_text‘
    }
};
var o2 = {
    txt1: ‘456‘,
    b: {
        ‘b_text‘: ‘123‘
    }
};
debugger;
var t = $.extend(false,o1,o2);

t[‘b‘][‘b_text‘] = ‘改变成文本‘;
console.log(t);
console.log(o1,o2);

// -----------------------------深度克隆------------------------------------
var o1 = {
   txt: "123",
    a: {
        ‘a_text‘: ‘a_text‘
    }
};
var o2 = {
    txt1: ‘456‘,
    b: {
        ‘b_text‘: ‘123‘
    }
};
debugger;
var t = $.extend(true,o1,o2);

t[‘b‘][‘b_text‘] = ‘改变成文本‘;
console.log(t);
console.log(o1,o2);

我们看当深度克隆参数为 false 的时候,扩展出来的对象 key 为 b 的和元素对象 key 为 b 的是指向的同一个引用。所以当我改变了克隆回来的对象 t 值 ‘b_text‘ 的时候原始对象也跟着变了。

再来看看深度克隆的情况,当我改变了克隆回来的对象 t 值 ‘b_text‘ 的时候原始对象没有跟着变了。


3、接下来看看为 jQuery 扩展插件的情况

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

他这里为 jQuery 静态函数 和 原型都添加了 extend 函数, 所以我们要编写插件只需要给原型添加一个扩展函数就可以啦。

$.fn.extend({tudou:function(){alert(‘hello tudou‘)}});

看一下他这里怎么实现的,其实原理很简单。

// 当扩展的对象只有一个的时候,就视为扩展 jQuery
if ( length === i ) {
	target = this;            // 修正 this 为jQuery
	--i;
}

当你只传递一个对象的时候他会把 扩展的目标指向当前 this,所以能很方便的进行插件编写。

好啦结束了。。。





jQuery剥皮二 - extend