jQuery源码阅读(一)---jQuery源码整体架构

之前用jQuery库写了两个小例子(结合Apache、PHP实现的简易聊天室以及音乐播放器),详见我的上两篇博客jQuery aJax技术以及PHP实现简单聊天室、 利用jQuery实现音乐播放器。为了更加深入了解jQuery库的架构以及巩固原生JS的基础和深度,决定刨一刨jQuery源码。

jQuery源码架构

首先,jQuery源码的整体构架如下:(此图来源于“jQuery技术内幕:深入解析jQuery架构设计与实现原理” 高云)
jQuery源码阅读(一)---jQuery源码整体架构_第1张图片

  1. 入口模块
    jQuery的入口模块,主要是创建jQuery对象。这块其实是比较绕的,涉及到JS 原型的概念。
  2. 底层模块
    jQuery的底层模块主要包括一些工具方法,以及比较底层的,用的比较多的函数方法。比如onConflict(),isArray(),isFunction(),makkeArray()等等,建议大家可以看看jQuery API手册
  3. 功能模块
    这块应该是我们平时用jQuery库用的比较多的方法。比如ajax请求,动画,事件处理,样式设置与获取,属性设置与获取等等,这些方法都依赖于底层模块的工具方法和浏览器功能测试,主要用于浏览器检测,解决浏览器兼容问题。同时,功能模块不同的方法也依赖于底层模块的各个不同方法。
    源码结构如下:
(function (window, undefined){
    //创建jQeury对象
    var jQuery = function(){
        var jQuery = function(selector, context){
            return new jQuery.fn.init(selector, context);
        }

        jQuery.fn = jQuery.prototype = function(){
            //原型上的方法,即所有jQuery对象都可以共享的方法和属性
        }
        jQuery.fn.init.prototype = jQuery.fn;
        window.jQeury = window.$ = jQuery;
    }();
})(window);

入口模块

本篇博客主要想解析的是入口模块。
首先是一个立即执行函数。

(function (window, undefined){
    //创建jQeury对象
})(window);

JS高程中函数-闭包这一章节就有讲到,原生JS中没有块级作用域的概念,但可以利用立即执行函数来模拟一个私有作用域。这样做是为了保证变量不被外面的变量影响。

另一方面,为什么要传window实参来执行函数呢?
window是顶级作用域,就算不传window参数进去,也同样可以访问到,但这就可能需要沿着作用域链一直去查找,导致时间比较长,而传入window参数之后,可以保证很快访问到。

下来在立即执行函数里面,是jQuery对象的创建。想想我们如何利用jQuery库来创建jQuery对象的?
直接$函数就能创建。

$("
jQuery源码
"
);

而在原生JS中,创建一个对象都是用new 和构造函数来实现的,那么看看jQuery源码中是如何做到的?

var jQuery = function( selector, context ) {
            // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context, rootjQuery );
    }

它是利用jQuery.fn.init方法来作为构造函数创建jQuery对象的。创建任何一个对象时,都会有与之对应的一个原型对象。为了使得以这个构造函数创建的每一个对象都有相同的属性和方法,要将其加到能连到jQuery的原型链上。可能这句话听着不是很明白,下面画一个图可以直观的缕一下:
在看到上面new jQuery.fn.init( selector, context, rootjQuery )操作之后,我们脑海中应该会有下面这幅图的样子:
jQuery源码阅读(一)---jQuery源码整体架构_第2张图片
下来我们想,如何将真正利用jQuery.fn.init()构造的对象与jQuery对象联系?即每一个构造出来的对象都可以共享一些相同的方法和属性,JS中原型链的概念可以帮助解决。因此,有了下面这幅图:
jQuery源码阅读(一)---jQuery源码整体架构_第3张图片
源码上如何实现?

jQuery.fn = jQuery.prototype = function(){
    init: function(selector, context, rootjQuery){
        //创建jQuery对象
    }
    //当然还有别的方法和属性   
}

jQuery.fn.init.prototype = jQuery.fn;

这样就可以保证创建出的jQuery对象可以连到jQuery原型链上了。

为了更好的理解,可能用代码来说话最有说服力。我简单实现了这一段。一方面,这样看着比源码简要的多;另一方面,源码中init构造函数涉及到很多种情况,这里先不介绍,仅用一小段代码来代替。

jQuery.lh.1.1.0.js

(function(window, undefined){
    var jQuery = (function(){
        var jQuery = function(selector, context){
            return new jQuery.fn.init(selector, context);
        }

        jQuery.fn = jQuery.prototype = {
            constructor: jQuery,
            init : function(selector, context){
                this.person = selector;
                this.name = context;
                return this;
            },
            sayHello : function(){
                console.log(this.name);
            }
        };
        jQuery.fn.init.prototype = jQuery.fn;
        window.$ = window.jQuery = jQuery;
    })();
})(window);

test.html


<html lang="en">
    <head>
        <meta charset="utf-8">
        <script src="jQuery.lh.1.1.0.js">script>
        <script>
            var o = jQuery("Hello", "Name");
            var s = $("LiuHuan", "Cname");
        script>
    head>
    <body>
    body>
html>

浏览器中调试模式下,o和s都分别是对象,有personname两个属性,并且有sayHello方法。
jQuery源码阅读(一)---jQuery源码整体架构_第4张图片
现在假设注释掉jQuery.fn.init.prototype = jQuery.fn;这一句代码,那么如果执行o.sayHello()会出现错误。原因就是因为实际用init构造的对象没有指回到jQuery对象的原型上,因此不能在原型链上访问到。
jQuery源码阅读(一)---jQuery源码整体架构_第5张图片

你可能感兴趣的:(Jquery源码系列)