`
niuqiang2008
  • 浏览: 12640 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

jQuery源码分析系列(01) : 整体架构

 
阅读更多

jQuery 2.0.3 源码分析core - 整体架构

拜读一个开源框架,最想学到的就是设计的思想和实现的技巧。

废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过,

不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery又给扫一遍

我也不会照本宣科的翻译源码,结合自己的实际经验一起拜读吧!

github上最新是jquery-master,加入了AMD规范了,我就以官方最新2.0.3为准

 

整体架构

jQuery框架的核心就是从HTML文档中匹配元素并对其执行操作、

例如:

$().find().css()
$().hide().html('....').hide().

从上面的写法上至少可以发现2个问题

1. jQuery对象的构建方式

2 .jQuery方法的调用方式

 

分析一:jQuery的无new构建

JavaScript是函数式语言,函数可以实现类,类就是面向对象编程中最基本的概念

复制代码
var aQuery = function(selector, context) {
        //构造函数
}
aQuery.prototype = {
    //原型
    name:function(){},
    age:function(){}
}

var a = new aQuery();

a.name();
复制代码

这是常规的使用方法,显而易见jQuery不是这样玩的

jQuery没有使用new运行符将jQuery显示的实例化,还是直接调用其函数

按照jQuery的抒写方式

$().ready() 
$().noConflict()

要实现这样,那么jQuery就要看成一个类,那么$()应该是返回类的实例才对

所以把代码改一下:

复制代码
var aQuery = function(selector, context) {
       return new aQuery();
}
aQuery.prototype = {
    name:function(){},
    age:function(){}
}
复制代码

通过new aQuery(),虽然返回的是一个实例,但是也能看出很明显的问题,死循环了!

 


那么如何返回一个正确的实例?

在javascript中实例this只跟原型有关系

那么可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中

复制代码
var aQuery = function(selector, context) {
       return  aQuery.prototype.init();
}
aQuery.prototype = {
    init:function(){
        return this;
    }
    name:function(){},
    age:function(){}
}
复制代码

当执行aQuery() 返回的实例:

image

很明显aQuery()返回的是aQuery类的实例,那么在init中的this其实也是指向的aQuery类的实例

问题来了init的this指向的是aQuery类,如果把init函数也当作一个构造器,那么内部的this要如何处理?

复制代码
var aQuery = function(selector, context) {
       return  aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        this.age = 18
        return this;
    },
    name: function() {},
    age: 20
}

aQuery().age  //18
复制代码

这样的情况下就出错了,因为this只是指向aQuery类的,所以需要设计出独立的作用域才行

 


jQuery框架分隔作用域的处理

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

很明显通过实例init函数,每次都构建新的init实例对象,来分隔this,避免交互混淆

那么既然都不是同一个对象那么肯定又出现一个新的问题

例如:

复制代码
var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        this.age = 18
        return this;
    },
    name: function() {},
    age: 20
}

//Uncaught TypeError: Object [object Object] has no method 'name' 
console.log(aQuery().name())
复制代码

抛出错误,无法找到这个方法,所以很明显new的init跟jquery类的this分离了

 


怎么访问jQuery类原型上的属性与方法?

     做到既能隔离作用域还能使用jQuery原型对象的作用域呢,还能在返回实例中访问jQuery的原型对象?

实现的关键点

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

通过原型传递解决问题,把jQuery的原型传递给jQuery.prototype.init.prototype

换句话说jQuery的原型对象覆盖了init构造器的原型对象

因为是引用传递所以不需要担心这个循环引用的性能问题

复制代码
var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this.age
    },
    age: 20
}

aQuery.prototype.init.prototype = aQuery.prototype;

console.log(aQuery().name()) //20
复制代码

百度借网友的一张图,方便直接理解:

fn解释下,其实这个fn没有什么特殊意思,只是jQuery.prototype的引用

 


分析二:链式调用

DOM链式调用的处理:

1.节约JS代码.

2.所返回的都是同一个对象,可以提高代码的效率

 

通过简单扩展原型方法并通过return this的形式来实现跨浏览器的链式调用。

利用JS下的简单工厂模式,来将所有对于同一个DOM对象的操作指定同一个实例。

这个原理就超简单了

aQuery().init().name()

分解
a = aQuery();
a.init()
a.name()

把代码分解一下,很明显实现链式的基本条件就是实例this的存在,并且是同一个

复制代码
aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this
    }
}
复制代码

所以我们在需要链式的方法访问this就可以了,因为返回当前实例的this,从而又可以访问自己的原型了

aQuery.init().name()

优点:节省代码量,提高代码的效率,代码看起来更优雅

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


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

 


分析三:插件接口

jQuery的主体框架就是这样,但是根据一般设计者的习惯,如果要为jQuery或者jQuery prototype添加属性方法,同样如果要提供给开发者对方法的扩展,从封装的角度讲是不是应该提供一个接口才对,字面就能看懂是对函数扩展,而不是看上去直接修改prototype.友好的用户接口,

jQuery支持自己扩展属性,这个对外提供了一个接口,jQuery.fn.extend()来对对象增加方法

从jQuery的源码中可以看到,jQuery.extend和jQuery.fn.extend其实是同指向同一方法的不同引用

jQuery.extend = jQuery.fn.extend = function() {
jQuery.extend 对jQuery本身的属性和方法进行了扩展

jQuery.fn.extend 对jQuery.fn的属性和方法进行了扩展

通过extend()函数可以方便快速的扩展功能,不会破坏jQuery的原型结构

jQuery.extend = jQuery.fn.extend = function(){...}; 这个是连等,也就是2个指向同一个函数,怎么会实现不同的功能呢?这就是this 力量了!

针对fn与jQuery其实是2个不同的对象,在之前有讲述:

  • jQuery.extend 调用的时候,this是指向jQuery对象的(jQuery是函数,也是对象!),所以这里扩展在jQuery上。
  • 而jQuery.fn.extend 调用的时候,this指向fn对象,jQuery.fn 和jQuery.prototype指向同一对象,扩展fn就是扩展jQuery.prototype原型对象。
  • 这里增加的是原型方法,也就是对象方法了。所以jQuery的api中提供了以上2中扩展函数。

extend的实现

复制代码
jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},   
 // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    
// 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   
// 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  
// jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) {
 // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不赘述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷贝,且被拷贝的属性值本身是个对象
                if ( deep && copy && ( jQuery.isPlainObject(copy) 
			|| (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷贝的属性值是个数组
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

                    // Never move original objects, clone them
                    target[ name ] = jQuery.extend( deep, clone, copy );  // 递归~

                // Don't bring in undefined values
                } else if ( copy !== undefined ) {  // 浅拷贝,且属性值不为undefined
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;
复制代码

 

 

总结:

  • 通过new jQuery.fn.init() 构建一个新的对象,拥有init构造器的prototype原型对象的方法
  • 通过改变prorotype指针的指向,让这个新的对象也指向了jQuery类的原型prototype
  • 所以这样构建出来的对象就继续了jQuery.fn原型定义的所有方法了

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    jQuery源码分析系列

    jQuery源码分析系列涉及了对jQuery库内部实现的详细解读,jQuery作为前端开发中最常用的JavaScript库之一,它简化了DOM操作、事件处理、动画效果和AJAX交互等操作。通过深入分析jQuery的源码,开发者可以学习到先进...

    jQuery源码分析系列.pdf

    综上所述,这份关于jQuery源码分析的系列文档,系统地梳理了jQuery库的各个组成部分,并且详细探讨了内部实现机制,为开发者提供了宝贵的学习资源,使得开发者能更深入地理解和使用jQuery,提高前端开发的效率和质量...

    jQuery 2.0.3 源码分析之core(一)整体架构

    在深入探讨jQuery 2.0.3源码中core部分的整体架构之前,我们先简要回顾一下jQuery框架的核心功能和其设计思想。jQuery是一个广泛使用的JavaScript库,主要用于简化HTML文档遍历和操作、事件处理、动画和Ajax交互。它...

    jQuery-sound-code:jQuery源码分析

    《jQuery源码分析》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM操作、事件处理、动画制作以及Ajax交互。本项目旨在深入解析jQuery的源码,通过分段解析、添加全中文注释和制作成手册的方式,帮助...

    jQuery源码+中文详细注解

    ### jQuery源码+中文详细注解 #### 一、引言 本文档是对jQuery源码进行中文注解的详细介绍,旨在帮助广大前端开发者更深入地理解jQuery的核心逻辑和技术要点。通过对核心部分的逐行注解,可以更好地掌握jQuery的...

    jquery的总体架构分析及实现示例详解

    本文将深入分析jQuery的总体架构,并提供实现示例,帮助读者理解其核心思想和设计技巧。 首先,jQuery的总体架构可大致分为三个主要部分: 1. **入口模块**:这是整个jQuery库的起点,通常是一个匿名函数自执行...

    jquery-easyui-1.5.3源代码(未压缩)

    1. 理解基本架构:首先了解EasyUI的整体设计思路和模块划分,熟悉主要的JavaScript对象和CSS类。 2. 分析组件实现:深入研究各个组件的源码,理解它们的工作原理和事件处理机制。 3. 调试与优化:通过断点、日志等...

    jquery 树的样本

    本文将深入探讨如何利用jQuery实现一个高效、易用的树形控件,并通过实例分析其核心原理和应用技巧。 ### 1. jQuery与树形结构 jQuery 是一个轻量级的 JavaScript 库,它简化了 HTML 文档遍历、事件处理、动画以及...

    jquery mobile

    **源码分析** jQuery Mobile 的源码结构清晰,模块化程度高。主要由以下几个部分组成: 1. **核心(Core)**:包括 DOM 操作、事件管理和动画等基础功能。 2. **页面管理(Page Management)**:处理页面加载、...

    jQuery实现的在线问卷答题系统效果源码.zip

    四、源码分析 在提供的压缩包中,"使用须知.txt"很可能是关于如何使用源码的说明,而"132679754053663868"可能是一个包含具体代码的文件,可能是HTML、CSS或JavaScript。深入研究这个文件,可以了解到实际的代码...

    ABP源码分析

    ### ABP源码分析 #### 一、整体项目结构及目录 ABP作为一个高度模块化且灵活可扩展的Web应用程序框架,其设计思路和技术选型都极具参考价值。本章节将着重探讨ABP项目的整体结构及其各个组成部分的功能定位。 ###...

    NopCommerce源码架构详解

    ### NopCommerce源码架构详解 #### 一、概述 NopCommerce是一个开源的企业级电子商务平台,使用.NET框架构建而成。它集成了多种先进的技术,包括但不限于Entity Framework、ASP.NET MVC、依赖注入(DI)以及插件化...

    kkFileView在线预览 v2.2.1-源码.zip

    《kkFileView在线预览 v2.2.1 源码分析与解析》 kkFileView是一款功能强大的在线文件预览工具,它允许用户无需下载文件就能在浏览器中查看各种类型的文档,如图片、文本、PDF、Office文档等。本次我们关注的是其v...

    Jquery + wcf团购网程序源码

    【jQuery + WCF 团购网程序源码】是一套基于.NET MVC框架和WCF服务构建的电子商务系统,主要用于实现类似团购网站的功能。这个源码采用三层架构设计,包括表现层(Presentation Layer)、业务逻辑层(Business Logic...

    基于spring+springmvc+mybatis+layui+jquery+bootstrap教材管理系统源码.zip

    这是一个典型的Java Web开发项目,使用了Spring、SpringMVC、MyBatis等主流技术栈,配合前端的Layui、jQuery和Bootstrap构建了一个教材管理系统。下面将详细解析这些技术及其在系统中的应用。 1. **Spring框架**:...

    java版中国象棋源码-twohand:二手书籍

    ①洪国栋:负责分配任务和资源、管理软件开发过程、保证团队目标的一致性、确保项目质量、获取需求、确立项目整体架构、对整个项目的技术活动和工作进行领导和协调。 ②李昌晋:对开发过程进行版本控制和产品规范。 ...

    web系统聊天源码

    1. **理解架构**:分析源码目录结构,了解整体架构和各模块之间的关系。 2. **前端交互**:研究前端代码,了解如何通过JavaScript与WebSocket接口交互。 3. **后端逻辑**:深入Java代码,理解WebSocket服务器的实现...

    java领航志远CMS源码源码整理

    同时,提供的“下载及使用说明.txt”可能包含关于系统安装、配置和运行的指导,这对于理解整体架构和功能很有帮助。“查看文件解压密码(网址即为解压密码).url”提供了获取解压密码的途径,确保正确解压并访问源码...

Global site tag (gtag.js) - Google Analytics