jQuery-1.9.1源码分析系列(一)整体架构

12/6/2015来源:Javascript教程人气:648

不废话,直接上关键。这个系列中有好些直接借用别人的资料,我将他们整合在自认为比较合理的地方。所以在此先谢谢那些前辈。

注意:后续系列中jQuery实例多用$(...)来表示

1.    初始化与链式调用基础


 

jQuery之所以能够链式调用在于每次调用返回来jQuery本身。实现关键代码如下。

 

jQuery = function(selector,context){
  return new jQuery.fn.init(selector,context,rootjQuery);
}
...
rootjQuery = jQuery(document);
...
jQuery.fn = jQuery.PRototype = {
  constructor: jQuery,
  init: function(selector,context,rootjQuery){
    ...
    return this;     ... } } ... jQuery.fn.init.prototype = jQuery.fn; ... window.jQuery = window.$ = jQuery;

  

需要有几个理解

a.    new的深度理解


 var obj = new Base();

这样代码的结果是什么,我们在javascript引擎中看到的对象模型是:

 

new操作符具体干了什么呢?其实很简单,就干了三件事情。

var obj = {};

obj.__proto__ = Base.prototype;

Base.call(obj);

第一行,我们创建了一个空对象obj;

第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象;

第三行,我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id(name,根据浏览器决定,Chrome是name属性)成员变量,这个成员变量的值是”Base”。

 

Base函数返回的结果会导致obj的结果不同。

举例(chrome下):

function Base(){
  this.name = “test”;
  this.a = “f”;
  return result;
}

1)     根据new的原理,如果没有返回值或返回值为数字或字符串或布尔类型,即result为null/number/string/bool,则new Base()返回的结果是本身,为

Base {name: "test", a: "f"}

2)     如果返回值为对象(数组或普通对象)或函数,则返回的对象或函数替换了Base本身;

拓展:

       new Base() == Base () 返回的结果为false

    例如当result为[]的时候,new Base()返回结果和Base()返回结果的都是[],但实际上他们并不相等 , Javascript  对于 Object 和 Function 的比较是基于引用的.

Var m = [],t = []; m == t;//false,并不是同一个引用

Var m = t = []; m == t;//true

b.    jQuery中jQuery.fn为什么表现为数组


 

jQuery将对象模拟成了数组,而如何让一个对象模拟成数组,jQuery给对象加上了以下几个属性:

{
  length: 0,
  push: [].push,
  sort: [].sort,
  splice: [].splice
},

不同的是chrome在给对象添加了length和splice后真的转化成了数组,如$()结果是[],而ie没有转化$()结果是{}。但是无所谓,他们都可以使用length等属性,不影响后续使用。如果$(…)有搜索结果,jQuery会把结果拼接成数组返回,这样jQuery的返回结果看起来总是数组。

 

总结


 

  由上面的分析可知jQuery.fn.init.prototype = jQuery.fn目的就是将jQuery.fn上的所有属性都挂在jQuery实例$(...)上,使得实例拥有很多jQuery.fn上定义的函数。比如jQuery.fn.extend函数,实例就可以直接使用:$(...).extend({"name": "chua"})。

  由于每次都是一个新的实例new jQuery.fn.init(selector,context,rootjQuery),所以各个实例是独立的。而jQuery全局的属性直接挂在jQuery上,比如jQuery.extend,这个和jQuery.fn.extend不一样了,因为jQuery.extend是全局的,比如jQuery.extend({"test": "chua"})你可以随时通过jQuery.test就把值给取出来了,而jQuery实例则需要保证同一个实例的情况下才能取到值。比如var ps = $("p").extend({"test": "chua"}),通过ps.test能够取到值,但是你使用$("p").test是取不到的。因为你使用$(...)又新建了一个实例。

  至于jQuery的链式调用很好理解,源码初始化的时候返回了jQuery对象本身:

init: function(selector,context,rootjQuery){
  ...
  return this;
}

  这一节先到这里,待续……