jQuery源码学习(1):整体架构

整体架构

$().find().css().hide()

从jQuery的表达式可以看出两点:

  1. jQuery的构建方式
  2. jQuery的调用方式

下面从这两方面来窥探jQuery的整体架构:

分析一:无new构建

这一点是推测jQ构建方式的重点。既然没有使用new,jQ必定在函数中返回了一个实例,也就是通过工厂模式来创建对象。

var aQuery = function(select){
var o = new Object();
o.select = select;
o.myFunc = function(){};
}

然而这种方法显然非常笨拙,每次新建一个对象实例都必须声明其所有共用方法。能不能把构造函数与原型模式融入到这里面来呢?

var aQuery = function(selector){
return aQuery.prototype.init(selector);
}; aQuery.prototype = { // aQuery的原型
init: function(selector){ // init作为新的构造函数
this.selector = selector;
return this;
},
myFunc: function(){}
}; console.log(aQuery('s1'));

代码运行之后,在控制台显示的是下面这样的结果:

{
init: [Function],
myFunc: [Function],
selector: 's1'
}

this指向了aQuery的原型对象,并且共用了所有方法。然而这里面的陷阱在于,由于我们并没有new一个新对象,所以构造函数内部的this指向了aQuery的原型,共享了本应该私有的属性。

var a1 = aQuery('s1');
var a2 = aQuery('s2');
console.log(a1.selector); // s2

那么是不是只要返回一个新实例就可以了呢?

var aQuery = function(selector, context){
return (new aQuery.prototype.init(selector, context));
}; aQuery.prototype = {...}; var a1 = aQuery('s1');
var a2 = aQuery('s2');
console.log(a1.selector); // s1
console.log(a1); //{ selector: 's1' } myFunc不见了!

由上可见,new关键字新建了一个空对象,使构造函数内部的this指向该对象,解决了属性公有的问题(这部分知识点请参考Javascript对象部分)。然而同时,也丢失了aQuery.prototype。那么jQuery是怎么解决这个问题的呢?这就是jQuery构建方法的关键所在:原型传递。

直接上代码:

var aQuery = function(selector){
return (new aQuery.prototype.init(selector));
}; aQuery.prototype = { // aQuery的原型
init: function(selector){ // init作为新的构造函数
this.selector = selector;
return this;
},
myFunc: function(){
return "aQuery.func";
}
};
aQuery.prototype.init.prototype = aQuery.prototype; var a1 = aQuery('s1');
var a2 = aQuery('s2');
console.log(a1.selector); // s1
console.log(a1.myFunc()); // aQuery.func

其实本质上讲,init构建出来的这个对象,就是jQuery对象。

这样,我们总算理清了jQuery无new构建的原理。使用工厂模式返回一个实例,并将该实例构造函数的原型指向aQuery原型本身,实现了私有属性和共有方法。

jQuery源码学习(1):整体架构

各中关系如图所示,其中fn指代了jQuery的原型对象。

分析二:链式调用

当使用了new关键字后,jQuery的所有方法中的this都指向了新建的实例,所以我们只要在方法最后返回this,就可以实现链式调用。然而:

摘自Aaron的JQ源码分析

最糟糕的是所有对象的方法返回的都是对象本身,也就是说没有返回值,这不一定在任何环境下都适合。

Javascript是无阻塞语言,所以他不是没阻塞,而是不能阻塞,所以他需要通过事件来驱动,异步来完成一些本需要阻塞进程的操作,这样处理只是同步链式,异步链式jquery从1.5开始就引入了Promise,jQuery.Deferred后期在讨论。

上一篇:一行一行分析JQ源码学习笔记-01


下一篇:一行一行分析JQ源码学习笔记-04