源码与扩展
源码
jQuery有很多设计是⾮常优秀的
The Write Less,Do More(写更少,做更多),⽆疑是JQuery的核⼼理念,简洁的API、优雅的链式、强⼤查询与便捷的操作。
经典细节1_⽴即执⾏函数
(function(global, factory){
...
})(typeof window !== "undefined" ? window : this, function( window,
noGlobal(){...});
Q:采⽤⽴即执⾏函数,这样做,有什么好处呢?
A:通过定义⼀个匿名函数,创建了⼀个新的函数作⽤域,相当于创建了⼀个“私有”的命名空间,该命名空间的变量和⽅法,不会破坏污染全局的命名空间。此时若是想访问全局对象,将全局对象以参数形式传进去即可。此外,新作⽤域内对象想访问传⼊的全局对象时,就不需要⼀步⼀步的往上找,可提⾼效率。
经典细节2_链式调⽤
$("div,parent").nextAll().first();
如何做到链式调⽤呢
var test = {
a:function(){
console.log('a');
return this;
},
b:function(){
console.log('b');
return this;
},
c:function(){
console.log('c');
}
}
test.a().b().c();
经典细节3_闭包下的重载
$('.test','td')
$(['.test','#id'])
$(function(){...})
$()
就是⼀个函数,参数不同,就涉及到了函数的重载。参数个数不等,⽤传统js
实现起来⾮常困难。那么jQuery究竟是如何实现的呢?
看⽤下⾯代码的实现
function addMethod( object, name, func ) {
var old = object[name];
object[name] = function(){
if(func.length === arguments.length){
return func.apply(this,arguments);
}else{
return old.apply(this,arguments);
}
}
}
var people = {
name:["a","b","c"]
}
var find0 = function(){
return this.name;
}
//新增
var find1 = function(name){
var arr = this.name;
for(var i = 0;i <= arr.length;i++ ){
if(arr[i]=name){
return arr[i];
}
}
}
addMethod(people,'find',find0);
//新增
addMethod(people,'find',find1);
console.log(people.find());//["a", "b", "c"]
console.log(people.find("a"));//a
经典细节4_init()
我们看如下截图
令⼈惊讶的是,new
出来的和直接调⽤的,居然是⼀模⼀样的。
这是为什么呢? 这就涉及到了jQuery
的经典的init
操作:
从上⾯这张图,我们可以了解到:
- 第⼀个红框:调⽤ jQuery ,返回的是
new
jQuery.fn.init(selector,context);
⽽init
⽅法被挂在到了jQuery.fn
上的。 - 第⼆个红框:
jQuery.fn = jQuery.prototype = {...};
为了⽅便讲解,我们对其进⾏⼀些简化:
//1
jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context );
}
//2
jQuery.fn = jQuery.prototype = {
init:function( selector, context ){
...
}
}
//3
init = jQuery.fn.init = function( selector, context, root ){
...
}
init.prototype = jQuery.fn;
步骤1:我们从代码块2开始看,
jQuery.prototype = jQuery.fn
,且都挂载了init()
函数。
步骤2:再看代码块3,jQuery.fn.init.prototype = jQuery.fn
,⽽我们从步骤1中,了解到jQuery.prototype = jQuery.fn
。因此jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
。
步骤3:最后,再回过来看代码块1,function
返回的是new jQuery.fn.init(..)
。我们再看步骤2,
jQuery.fn.init.prototype = jQuery.prototype
。那么,new jQuery.fn.init(..)
就相当于function
返回了⼀个new jQuery()。
饶了⼀⼤圈,就相当于 jQuery = new JQuery();
Q:那么,为啥要绕那么远呢?
A:为了得到jQuery原型链上的⽅法。
扩展
接下来我们扩展jQuery⽅法
- 扩展⼀个
print()
⽅法,获得当前元素的内容
$.fn.extend({
print:function(){
console.log($(this).html())
}
})
$("p").print();
- 我们也可以传递参数
(function($){
$.fn.print=function(options){
$(this).html(options)
}
})(jQuery);
$("p").print("demo")