jQuery的extend方法

    这篇文章,来源于一场事故...

    关于,今天会写这个小结,也是来源于一场小事故。为了偷懒,就喜欢将一些方法,封装起来,只暴露一个接口,通过传入指定的参数,只调用一个API就能做成一件小事。那么不可避免,我们就需要给这个方法设置一些默认的参数,然后通过传入的参数去覆盖它,或者通过它来写一个jQuery的插件。于是,就理所当然的用了jQuery的extend().

   相信大部分的人都非常的熟悉jQuery,也十分的熟悉jQuery用来合并对象和扩展方法的extend().但是,有些时候,我们在开发中,要把jQuery的功能用到淋漓尽致,充分发挥它的才能的时候,其实很少。我们不可能说只是为了用jQuery的选择器,或者只是为了用它的extend方法,就把整个库都引入我们的工程当中去,那真是十分耗资源。  

   于是先写了个1.0的low版本用来扩展属性

var Kingsley = function(){};

//v1.0
Kingsley.prototype.extend = fucntion(defaults,parameters){

	for(var param in parameters){
		if(defaults.hasOwnProperty(param) && parameters.hasOwnProperty(param)){
			defaults[param] = parameters[param];
		}
	}

	return defaults;
}

     但是,很快就发现了不足。于是做了些改进,有了2.0版本

Kingsley.prototype.extend = function(){

	var options,target,copy,src,
	 	i = 1,
		len = arguments.length;

	target = arguments[0];

	for(;i < len;i++){

		if((options = arguments[i]) != null){

			for(var param in options){

				if(target.hasOwnProperty(param) && options.hasOwnProperty(param)){

					src = target[param];
					copy = options[param];

					if(typeof src === "object"){

						target[param] = Kingsley.prototype.extend(src,copy);
		
					}else{
						target[param] = copy;
					}
				}
			}
		}
	}

	return target;

}

      2.0的版本看起来稍微有点起色了,但好像也不好,还是需要改进。

      于是呢。。。铺垫了这么久,该上jQuery的源代码了。

      我们先来看

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

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;

		// Skip the boolean and the target
		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
	if ( i === length ) {
		target = this;
		i--;
	}

	for ( ; 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
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = jQuery.isArray( copy ) ) ) ) {

					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray( src ) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject( src ) ? src : {};
					}

					// 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;
};

     一看,就很容易看出区别了。jQuery的代码写的非常的优雅,而且做了许多了处理机制,防止意外发生。

     调用jQuery的extend,除了可以扩展属性,还能用来扩展jQuery的静态方法和实例方法。

     1.$.extend(true,defaults,options);

     2.$.extend({say:function(){ alert("Hello World")}});

     我们把它一部分一部分拆解开来

// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;

		// Skip the boolean and the target
		target = arguments[ i ] || {};
		i++;
	}

很明显 ,deep是我们传入的第一个参数,这个参数也是为了告诉jQuery,我们进行的是深拷贝还是浅拷贝。所谓的深拷贝,其实就是,当你进行多个参数的合并后,如果改变了某个对象的属性的值,相应的对象的属性会不会也发生了改变。深拷贝是相互独立的。改变了一个属性的值,并不会影响到另一个属性的值。

// 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
if ( i === length ) {
	target = this;
	i--;
}

上面这段代码,只是做了个简单的判断。如果传入的参数不是对象,或者不是一个函数,那么就把它初始化为一个空对象。而target = this,则是在只传入一个对象的时候,把jQuery本身赋值给了target。这么做的目的,就是为了能够在jQuery上扩展方法。


for ( ; 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
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = jQuery.isArray( copy ) ) ) ) {

					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray( src ) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject( src ) ? src : {};
					}

					// 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;
				}
			}
		}
	}

后面的这一大串,大部分所作的事情,就是为了将一个对象的属性扩展到另一个对象的身上。其中,比较关键的是

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

// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );

前者为了防止死循环,而后者,则是在出现对象的属性又是个对象的时候如何解决,那就是递归又调用了自己。


嗯。其实非常简单,但是,能够写得优雅,其实并不容易。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值