不需要new关键字创建实例?jQuery是如何做到的

news2025/1/10 20:47:03

  这篇文章是jQuery源码专栏的开篇文章了,有人会问为什么都2024年了, 还要研究一个已经过时的框架呢,其实,jQuery对比vue和react这种响应式框架,其在使用上算是过时的,毕竟直接操作DOM远不如操作虚拟DOM来的方便,但是jQuery的框架设计和对于操作的封装以及浏览器的兼容这些,太值得我们去学习了。

  这个专栏更新的速度不会快,这框架代码我是刚开始进行了解,所以只能边看边查资料边写,但是肯定会完成这个专栏的, 做完这个专栏,后面还会有其它框架或者三方库源码的解析,写上来也是为了强制要求一下自己去学习。

正文

  为什么在使用jQuery的时候,直接$()就可以调用.css(), .val() 这样的实例方法呢?以v3.7.1代码为例,看一下jQuery做了些什么。

        // Define a local copy of jQuery
        jQuery = function (selector, context) {

            // The jQuery object is actually just the init constructor 'enhanced'
            // Need init if jQuery is called (just allow error to be thrown if not included)
            return new jQuery.fn.init(selector, context);
        };

这段代码定义了一个函数,函数的返回值为jQuery.fn.init函数的执行结果,并将返回值赋给名为jQuery的变量。为什么返回init的执行结果,而不是直接return new jQuery() 呢,改写一下试试。

    var jQuery = function () {
        return new jQuery()
    }
    jQuery()

打开浏览器控制台看一下:
请添加图片描述
哦吼,报错了,栈溢出了,因为上述的代码一直在循环调用jQuery()这个构造函数,死循环了。

所以,jQuery为了避免这个问题,另外指定了一个构造函数init()。

接下来就要聚焦一下init这个构造函数都做了什么

jQuery.fn.init

  先贴一下源代码

        jQuery.fn.init = function (selector, context, root) {
            var match, elem;  

            // HANDLE: $(""), $(null), $(undefined), $(false)
            if (!selector) {
                return this;
            }

            // Method init() accepts an alternate rootjQuery
            // so migrate can support jQuery.sub (gh-2101)
            root = root || rootjQuery;

            // Handle HTML strings
            if (typeof selector === "string") {
                if (selector[0] === "<" &&
                    selector[selector.length - 1] === ">" &&
                    selector.length >= 3) {

                    // Assume that strings that start and end with <> are HTML and skip the regex check
                    match = [null, selector, null];

                } else {
                    match = rquickExpr.exec(selector);
                }

                // Match html or make sure no context is specified for #id
                if (match && (match[1] || !context)) {

                    // HANDLE: $(html) -> $(array)
                    if (match[1]) {
                        context = context instanceof jQuery ? context[0] : context;

                        // Option to run scripts is true for back-compat
                        // Intentionally let the error be thrown if parseHTML is not present
                        jQuery.merge(this, jQuery.parseHTML(
                            match[1],
                            context && context.nodeType ? context.ownerDocument || context : document,
                            true
                        ));

                        // HANDLE: $(html, props)
                        if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
                            for (match in context) {

                                // Properties of context are called as methods if possible
                                if (isFunction(this[match])) {
                                    this[match](context[match]);

                                    // ...and otherwise set as attributes
                                } else {
                                    this.attr(match, context[match]);
                                }
                            }
                        }

                        return this;

                        // HANDLE: $(#id)
                    } else {
                        elem = document.getElementById(match[2]);

                        if (elem) {

                            // Inject the element directly into the jQuery object
                            this[0] = elem;
                            this.length = 1;
                        }
                        return this;
                    }

                    // HANDLE: $(expr, $(...))
                } else if (!context || context.jquery) {
                    return (context || root).find(selector);

                    // HANDLE: $(expr, context)
                    // (which is just equivalent to: $(context).find(expr)
                } else {
                    return this.constructor(context).find(selector);
                }

                // HANDLE: $(DOMElement)
            } else if (selector.nodeType) {
                this[0] = selector;
                this.length = 1;
                return this;

                // HANDLE: $(function)
                // Shortcut for document ready
            } else if (isFunction(selector)) {
                return root.ready !== undefined ?
                    root.ready(selector) :

                    // Execute immediately if ready is not present
                    selector(jQuery);
            }

            return jQuery.makeArray(selector, this);
        };

很长的一段代码,不过大多都是在处理$()内部传入的不同类型的选择器,暂时不关注如何对选择器进行处理,直接简化代码:

    jQuery.fn.init = function () {
        return this
    }

去掉了目前不关注的选择器处理,init这个函数就只是返回了一个自身的this,那么问题来了, 这个this指向init,jQuery里面的那些方法init里面又没有提供,还是不能通过$().xxx() 来实现函数的调用呀。

没事儿,接着看代码:

init.prototype = jQuery.fn;

jQuery.fn 其实就是 jQuery.prototype,语义上更容易理解,就是jQuery的实例方法。
上述代码init.prototype 引用 jQuery.prototype ,意味着init就是jQuery对象。

现在可知init就是jQuery,那么,jQuery.fn.init() 就是创建jQuery的构造函数。

现在我们可以以jQuery的风格来编写一段创建jQuery实例的代码:

    var jQuery = function () {
        return new jQuery.fn.init()
    }

    jQuery.fn = jQuery.prototype = {
        each: function () {
            console.log('each', this)
            return this
        }
    }

    jQuery.fn.init = function () {
        return this
    }

    jQuery.fn.init.prototype = jQuery.fn

    var $ = jQuery
    console.log($().each())

运行结果:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1854845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣SQL50 游戏玩法分析 IV 子查询

Problem: 550. 游戏玩法分析 IV &#x1f468;‍&#x1f3eb; 参考题解 这个SQL查询的目的是计算每个玩家在登录后的第二天参与活动的比例。查询使用了子查询和左连接来实现这一目的。下面是查询的详细解释&#xff0c;包括每个部分的作用和注释&#xff1a; -- 计算每个玩…

LLm与微调入门

前言 两种 Finetune 范式 增量预训练微调 使用场景&#xff1a;让基座模型学习到一些新知识&#xff0c;如某个垂类领域的常识 训练数据&#xff1a;文章、书籍、代码等 指令跟随微调 使用场景&#xff1a;让模型学会对话模板&#xff0c;根据人类指令进行对话 训练数据…

C++第二学期期末考试选择题题库(qlu题库,自用)

又到了期末周&#xff0c;突击一下c吧— 第一次实验 1、已知学生记录的定义为&#xff1a; struct student { int no; char name[20]; char sex; struct 注意年月日都是结构体&#xff0c;不是student里面的 { int year; int month; …

数据分析BI仪表盘搭建

BI仪表盘搭建六个原则&#xff1a; 1.仪表盘搭建符合业务的阅读&#xff0c;思考和操作逻辑。 2.明确仪表盘主题&#xff0c;你的用户对什么感兴趣。 普通业务人员&#xff1a;销售&#xff1a;注册&#xff0c;激活&#xff0c;成交投放&#xff1a;消耗&#xff0c;转化率…

构建下一代数据解决方案:SingleStore、MinIO 和现代 Datalake 堆栈

SingleStore 是专为数据密集型工作负载而设计的云原生数据库。它是一个分布式关系 SQL 数据库管理系统&#xff0c;支持 ANSI SQL&#xff0c;并因其在数据引入、事务处理和查询处理方面的速度而受到认可。SingleStore 可以存储关系、JSON、图形和时间序列数据&#xff0c;以满…

Java面试八股之简述JVM内存结构

简述JVM内存结构 Java虚拟机&#xff08;JVM&#xff09;内存结构主要分为线程私有区域和线程共享区域两大部分&#xff0c;具体组成部分如下&#xff1a; 线程私有区域 程序计数器&#xff08;Program Counter Register&#xff09;&#xff1a; 记录当前线程执行的字节码行…

24-6-23-读书笔记(七)-《文稿拾零》豪尔赫·路易斯·博尔赫斯(第三辑)

文章目录 《文稿拾零》阅读笔记记录总结 《文稿拾零》 《文稿拾零》超厚的一本书&#xff08;570&#xff09;&#xff0c;看得时间比较长&#xff0c;这本书是作者零散时间写的一些关于文学性质的笔记&#xff0c;读起来还是比较无趣的&#xff0c;非常零散&#xff0c;虽然有…

CP AUTOSAR标准之FlashTest(AUTOSAR_CP_SWS_FlashTest)(更新中……)

1 简介和功能概述 该规范指定了AUTOSAR基础软件模块Flash测试驱动程序的功能、API和配置。   此闪存测试模块提供测试恒定内存的算法。恒定内存可以是数据/程序闪存、程序SRAM、锁定缓存,可以嵌入微控制器中,也可以通过内存映射连接到微控制器。为简化起见,SW模块称为闪存…

秋招突击——第六弹——Java的SSN框架快速入门——MyBatisPlus

文章目录 引言正文入门案例整和MybatisPlus的相关内容 概述标准数据层开发分页查询DQL编程控制条件查询——NULL值处理 查询投影查询条件设定等于操作范围查询模糊查询分组查询 字段映射和表名映射 DML编程控制——增删改查相关操作添加操作id生成策略控制 删除操作多数据删除逻…

面试:关于word2vec的相关知识点Hierarchical Softmax和NegativeSampling

1、为什么需要Hierarchical Softmax和Negative Sampling 从输入层到隐含层需要一个维度为NK的权重矩阵&#xff0c;从隐含层到输出层又需要一个维度为KN的权重矩阵&#xff0c;学习权重可以用反向传播算法实现&#xff0c;每次迭代时将权重沿梯度更优的方向进行一小步更新。但…

Qt画实时曲线图

Qt引入QcustomPlot 首先下载QcustomPlot源代码&#xff0c;https://github.com/qcustomplot/qcustomplot 下载zip文件 运行所下载的项目生成库文件libqcustomplotd2.a文件和qcustomplotd2.dll文件。 在项目中添加printsupport。 并将qcustomplot.h文件和qcustomplot.cpp文…

RMDA通信1:通信过程和优势,以太网socket为何用户空间拷贝到内核空间

视频分享&#xff1a; 1.1 RDMA基本原理和优势&#xff0c;以太网socket通信为什么要用户空间拷贝到内核空间_哔哩哔哩_bilibili 一、以太网socket通信 1.1 以太网socket通信过程 1、发送端发起一次通信操作&#xff0c;数据由用户空间拷贝到内核空间。拷贝由CPU完成&#x…

ubuntu22.04笔记: 更换为阿里源

没有按照LTS 版本 会遇到下面问题&#xff1a; 参考&#xff1a;https://zhuanlan.zhihu.com/p/691625646 Ubuntu 22.04代号为&#xff1a;jammy Ubuntu 20.04代号为&#xff1a;focal Ubuntu 19.04代号为&#xff1a;disco Ubuntu 18.04代号为&#xff1a;bionic Ubuntu …

【算法专题--链表】两两交换链表中的节点 -- 高频面试题(图文详解,小白一看就懂!!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐双指针 -- 采用哨兵位头节点 &#x1f95d; 什么是哨兵位头节点&#xff1f; &#x1f34d; 解题思路 &#x1f34d; 案例图解 四、总结与提炼 五、共勉 一、前言 两两交换链表中的节点 这道题&#xff0c;可以说…

libssh-cve_2018_10933-vulfocus

1.原理 ibssh是一个用于访问SSH服务的C语言开发包&#xff0c;它能够执行远程命令、文件传输&#xff0c;同时为远程的程序提供安全的传输通道。server-side state machine是其中的一个服务器端状态机。 在libssh的服务器端状态机中发现了一个逻辑漏洞。攻击者可以MSG_USERA…

从零开始搭建一个酷炫的个人博客

效果图 一、搭建网站 git和hexo准备 注册GitHub本地安装Git绑定GitHub并提交文件安装npm和hexo&#xff0c;并绑定github上的仓库注意&#xff1a;上述教程都是Windows系统&#xff0c;Mac系统会更简单&#xff01; 域名准备 购买域名&#xff0c;买的是腾讯云域名&#xf…

重庆交通大学24计算机考研数据速览,专硕第二年招生,复试线321分!

重庆交通大学&#xff08;Chongqing Jiaotong University&#xff0c;CQJTU&#xff09;&#xff0c;是由重庆市人民政府和中华人民共和国交通运输部共建的一所交通特色、以工为主的多科性大学&#xff0c;入选“中西部高校基础能力建设工程”、“卓越工程师教育培养计划”、国…

Chromium 调试指南2024 - 远程开发(下)

1. 引言 在《Chromium 调试指南2024 - 远程开发&#xff08;上&#xff09;》中&#xff0c;我们探讨了远程开发的基本概念、优势以及如何选择合适的远程开发模式。掌握了这些基础知识后&#xff0c;接下来我们将深入了解如何在远程环境中高效地进行Chromium项目的调试工作。 …

Visual Studio开发环境搭建

原文&#xff1a;https://blog.c12th.cn/archives/25.html Visual Studio开发环境搭建 测试&#xff1a;笔记本原装操作系统&#xff1a;Windows 10 家庭中文版 资源分享链接&#xff1a;提取码&#xff1a;qbt2 注意事项&#xff1a;注意查看本地硬盘是否够用&#xff0c;建议…

C语言中的字符输入/输出和验证输入

在C语言中&#xff0c;字符输入/输出功能允许程序与用户进行交互&#xff0c;读取用户的输入信息并展示输出结果。同时&#xff0c;验证输入的作用在于确保用户输入的数据符合预期&#xff0c;以提高程序的稳定性和可靠性&#xff0c;防止无效输入引发的错误或异常行为&#xf…