jQuery中,$.extend,$obj.extend和$.fn.extend三者的区别
现在做的一个项目,所使用的框架是基于jQuery扩展的,于是平时学了一下jQuery,了解到了它的扩展函数:extend
关于这个函数,这篇文章已经做了很好的介绍,这里只是补充一下我的疑问和见解。
当我读了上面链接的这篇文章后,产生了个疑问:$.extend和$.fn.extend到底区别在哪呢?API说前者是将扩展成员合并到全局对象中去,后者是将扩展成员合并到实例对象中去。我看不明白这两句话,于是亲自试了一下,结果发现,两个函数的作用貌似是一样的,都是将后面几个参数所指定的扩展成员合并到第一个参数对象中。
接着我又看了下这个函数的源码,代码并不多。首先第一句声明就让我觉得这两个函数其实是一样的了:
jQuery.extend = jQuery.fn.extend = function() {}
没错。这两个函数确实是同一个。如果在里面打上断点,那么无论通过哪种方式调用都会在断点处中断。
不过上面的引文还提到了一点:如果只传了一个参数,也就是target参数(如果第一个参数是boolean类型那么target参数是第二个),那么“target参数”就会成为“扩展成员”(option),被扩展的对象则是调用extend函数的对象。因此,通过这两种方式调用,函数体里面的this所指向的对象不同,因此实现的功能就不一样了。
接着看一下调用extend函数的三种方式(这里都特指只传一个参数,或者第一个参数是boolean的前提下只传两个参数的情形,因为传更多的参数的话,这些调用方式的作用貌似是一样的):
$.extend
$("#id").extend
$.fn.extend
下面针对以上三个调用者,对jQuery的代码结构简化一下。
1 (function( window, undefined ) { 2 var jQuery = function( selector, context ) { 3 // The jQuery object is actually just the init constructor 'enhanced' 4 return new jQuery.fn.init( selector, context, rootjQuery ); 5 }, 6 jQuery.fn = jQuery.prototype = { 7 // ... 8 init: function(...) {}, 9 // ... 10 }; 11 jQuery.fn.init.prototype = jQuery.fn; 12 jQuery.extend = jQuery.fn.extend = function() {}; 13 window.jQuery = window.$ = jQuery; 14 }(window);
可以按照这个思路理解上面贴出的代码。当jQuery文件被加载完成后,闭包立刻执行,并且传入了window全局变量。然后在13行定义了window.jQuery和window.$,因此你可以在你代码的任何地方使用jQuery函数或者$函数,它俩是一样的东西。接着看它们共同指向的对象,是一个函数,调用这个函数会返回一个jQuery.fn.init类型的对象,换句话说。你调用$(...)或者jQuery(...)所得到的任何东西,都是jQuery.fn.init这个函数new出来的对象。然而,若用instanceOf来测试这些对象的类型,发现他们是jQuery类的对象。这是因为在11行,init的原型指向了jQuery.fn,而且在第6行,fn指向了jQuery.prototype。对于表达式a instanceOf b,只要在a的原型链中能够找到b,就会返回true。当然,通过a也可以调用b的所有成员和方法。
到此,应该很容易理解下面贴出的测试代码和测试结果:
1 $(function(){ 2 var $p = $("#panel"); 3 var $p2 = $("#panel2"); 4 $p.extend({key1: "value1"}); 5 $p2.extend({key2: "value2"}); 6 $.extend({key3: "value3"}); 7 $.fn.extend({key4: "value4"}); 8 // 通过$px.extend只影响$px自身 9 console.log($p.key1); // value1 10 console.log($p2.key1); // undefined 11 console.log($p.key2); // undefined 12 console.log($p2.key2); // value2 13 console.log($.key1); // undefined 14 console.log($.key2); // undefined 15 // 通过$.extend只影响$自身 16 console.log($.key3); // value3 17 console.log($p.key3); // undefined 18 console.log($p2.key3); // undefined 19 // 通过$.fn.extend影响所有$px和$.prototype 20 console.log($p.key4); // value4 21 console.log($p2.key4); // value4 22 console.log($.prototype.key4); // value4 23 console.log($.key4); // undefined 24 });
最后总结一下结论:
1。如果传入了两个以上,或者第一个参数是boolean类型,传入了三个以上参数时,三种调用方式的效果是一样的。
2。否则,$.extend只是扩展了$这个函数自身;
$("#id").extend只扩展了$("#id")这个jQuery对象自身;
$.fn.extend扩展了jQuery对象的原型,可以通过所有的jQuery对象调用扩展成员,但不能通过$调用。