jQuery分析(2) - $工厂函数分析

jQuery分析(2) - $工厂函数分析

前言

从这节进入jQuery的世界,首先从jQuery的入口函数开始了解jQuery()或$是如何运作的,这里我给出了一个最小的例子来分析。

回忆

在进入分析代码前我们回想下jQuery的使用方法有哪些呢?

  • selector,[context]

    • selector:用来查找的字符串
    • context:作为待查找的 DOM 元素集、文档或 jQuery 对象。
  • element
    • 一个用于封装成jQuery对象的DOM元素
  • object
    • 一个用于封装成jQuery对象
  • elementArray
    • 一个用于封装成jQuery对象的DOM元素数组。
  • jQuery object
    • 一个用于克隆的jQuery对象。
  • jQuery()
    • 返回一个空的jQuery对象。

大家知道$函数等于jQuery函数,在调用完$函数后它会选择出传递第一个参数对应的元素或创建一个新元素,如果给定了第二个参数(context)那就是从context这个上下文向下查找。实现原理并不难,复杂的是涉及的逻辑相对多和兼容性问题。接下来是我整理的一个jQuery最小框架,我们一起来看看jQuery如何实现$(‘div‘).width()神奇的方法。

jQuery库本质的实现原理(对象模拟数组)源码 官方完整源码地址 / 简化版源码地址

(function() {
    var jQuery = function(selector) {
        return new jQuery.fn.init(selector);
    };
    jQuery.fn = jQuery.prototype = {
        selector: "",
        length: 0,
        constructor: jQuery,
        find: function(selector) {
            var ret = [];
            ret.push(document.getElementById(selector));
            ret = this.pushStack(ret);
            ret.selector = selector;
            return ret;
        },
        pushStack: function(elems) {
            var ret = this.constructor();
            for(var i = 0, il = elems.length; i < il; i++) {
                ret[i] = elems[i];
            }
            ret.length = i;
            ret.prevObject = this;
            ret.context = this.context;
            return ret;
        },
        msg: function() {
            console.log(‘test function‘);
        }
    };

    var init = jQuery.fn.init = function(selector) {
        if(!selector) {
            return this;
        }
        if(typeof selector == ‘string‘) {
            return rootjQuery.find(selector);
            //return document.getElementById(selector);
        } else if(selector.nodeType) {
            this.context = this[0] = selector;
            this.length = 1;
            return this;
        }
    };
    init.prototype = jQuery.fn;
    var rootjQuery = jQuery(document);
    window.$ = jQuery;
})();

上面的代码是我在抛开了jQuery的其他逻辑后整理出来它的架构的基础,接着一步一步来仔细看看他是如何运行的。

jQuery框架核心步骤

  • 对于一个jQuery对象的调用分2种:

    • 新选择一个元素或者创建一个元素(在jQuery函数中new一个jQuery.fn.init构造函数)
    • 执行一个jQuery对象方法(执行jQuery在原型链上的方法)
  • 对传入的selector进行不同操作解析(不传入任何参数将返回一个空的jQuery对象实例)
  • 对于传入一个选择器参数进行find查找元素,对于传入字符串参数进行DOM解析创建元素
  • 创建一个新的jQuery对象,将以上选择好的元素或者创建好的DOM节点用数组的方式合并到新的jQuery对象中并返回

$(‘div‘) 方法调用顺序图

框架代码关键点

  • jQuery.fn = jQuery.prototype
  • jQuery.fn.init
  • pushStack

jQuery.fn = jQuery.prototype 这个对象是jQuery对象的原型链当使用 $(‘div‘) 创建出来的jQuery对象便拥有改对象的所有方法

jQuery.fn.init 函数对传入的参数selector进行不同类型的解析,如果selector是一个字符串则找到他的id的元素。

jQuery.fn.init = function(selector) {
    if (!selector) {
        return this;
    }
    if (typeof selector == ‘string‘) {
        // 是字符串则找到这个字符串id的元素
        return rootjQuery.find(selector);
    } else if (selector.nodeType) {
        // 如果是dom元素直接赋值和修正length,最后返回this
        this.context = this[0] = selector;
        this.length = 1;
        return this;
    }
};

pushStack首先创建一个空的jQuery对象,然后把查找到的元素合并到空对象中并进行length修正,最后修改prevObject以便最上次操作的元素进行跟踪(详细请见end()函数)

pushStack: function(elems) {
    // 创建一个空的jQuery对象
    var ret = this.constructor();
    // 把找到的元素放入ret空对象中
    for (var i = 0, il = elems.length; i < il; i++) {
        ret[i] = elems[i];
    }
    // 修正length
    ret.length = i;
    // 跟踪上次更改元素操作
    ret.prevObject = this;
    // 修正上下文
    ret.context = this.context;
    // 返回装好元素的jQuery对象
    return ret;
}

调用jQuery.prototype原型链上的msg函数示例

var elem = $(‘div‘);
elem.msg();    // test function

总结

分析jQuery或$函数执行流程,用简化版例子分析jQuery从入口函数到返回jQuery对象过程中都做了什么事情并且对 $(‘div‘).msg() 调用方法进行了分析。通过这个简化版例子了解jQuery的基础架构。这对于以后的学习是必要。

如有疏忽、遗漏、错误请狠狠批评谢谢。

转载:http://www.cnblogs.com/monsterooo/p/5479642.html

时间: 2024-10-08 08:11:42

jQuery分析(2) - $工厂函数分析的相关文章

gcc源代码分析,expand_call ()函数分析第五部分,store_one_arg ()函数

本文主要是分析store_one_arg ()函数和expand_expr ()的关系来说明如何处理 函数的参数.printf("Hello, world!\n");中的"Hello, world!\n"这个字符串常量的! expand_call () 函数中的相关代码: if (args[i].reg == 0 && TYPE_SIZE (TREE_TYPE (args[i].tree_value)) != 0) { fprintf(stderr,

gcc源代码分析,build_pointer_type ()函数分析

function = build (ADDR_EXPR, build_pointer_type (TREE_TYPE (function)), function); 继续分析上篇文章的这句. /* Constructors for pointer, array and function types. (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are constructed by language-dependent code, not he

gcc源代码分析,grokparms ()函数分析

arg_types = grokparms (TREE_OPERAND (declarator, 1), funcdef_flag /* Say it's a definition only for the CALL_EXPR closest to the identifier.  */ && TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE); <tree_list 956b0 permanent purpose

Flask框架工厂函数用法实例分析

在我们开始学习FLask的时候,创建应用的实例是用app=Flask(name)来做的,但是当我们想创建多个不同配置的实例的时候咋办呢,每次都要改是不是很烦,那为了减少麻烦,我们可以采用调用一个create_app函数来返回应用实例的方法,这就是工厂方法的大概意思啦! 文字说的再多也难以帮助理解,看代码示例: 1.最初的写法 ? 1 2 3 4 5 6 7 8 #__init__.py里面创建实例,应用实例对象创建完再引入视图函数的模块,因为这时候视图函数上的@app.route()才有效 fr

jQuery之ajax错误调试分析

jQuery之ajax错误调试分析 jQuery中把ajax封装得非常好.但是日常开发中,我偶尔还是会遇到ajax报错.这里简单分析一下ajax报错 一般的jQuery用法如下,ajax通过post方式提交"汤姆和老鼠"这段数据到xxx.php文件中.成功后则打印返回的数据,失败则打印错误原因. 1 2 3 4 5 6 7 8 9 10 $.ajax({     url:"xxx.php",     type:"post",     dataty

JQuery data API实现代码分析

JQuery data 接口是什么? .data() Store arbitrary data associated with the matched elements or return the value at the named data store for the first element in the set of matched elements. 根据jquery官网介绍,data给存储DOM关联的数据, 设置数据是对$选取的所有JQuery对象, 获取数据是对$选取的所有对象的

jQuery源码解读-事件分析

最原始的事件注册 addEventListener方法大家应该都很熟悉,它是Html元素注册事件最原始的方法.先看下addEventListener方法签名: element.addEventListener(event, function, useCapture) event:事件名,例如“click”,这里要提醒的一点是不要加前缀“on”;    function:事件触发时执行的函数;    userCapture:默认为false,表示event事件在冒泡阶段触发.如果设置为true,则

【E2LSH源码分析】E2LSH函数接口

上一小节,我们对E2LSH代码主要的源码框架和用到的数据结构作了简单介绍(http://blog.csdn.net/jasonding1354/article/details/38331229),这一节我将简单介绍一下E2LSH的主要函数接口. 1.构建R-NN数据结构(定义在NearNeighbors.h) 输入为1-δ.R.d和数据集P,利用下面函数来构建: PRNearNeighborStructT initSelfTunedRNearNeighborWithDataSet(RealT t

linux C函数之strdup函数分析

一.函数分析 1.函数原型: #include <string.h>char *strdup(const char *s); 2.功能: strdup()函数主要是拷贝字符串s的一个副本,由函数返回值返回,这个副本有自己的内存空间,和s没有关联.strdup函数复制一个字符串,使用完后,要使用delete函数删除在函数中动态申请的内存,strdup函数的参数不能为NULL,一旦为NULL,就会报段错误,因为该函数包括了strlen函数,而该函数参数不能是NULL. 3.strdup函数实现 c