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

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

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

正文

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

        // Define a local copy of jQueryjQuery = 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 stringsif (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 checkmatch = [null, selector, null];} else {match = rquickExpr.exec(selector);}// Match html or make sure no context is specified for #idif (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 presentjQuery.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 possibleif (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 objectthis[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 presentselector(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.fnvar $ = jQueryconsole.log($().each())

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

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

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

相关文章

Python 深入学习局部函数和闭包函数

目录 局部函数与闭包函数的关联 变量捕获与状态保留 应用场景的交集与差异 闭包的本质 局部函数示例 闭包函数示例 局部函数和闭包函数之间存在着密切的联系&#xff0c;同时也有一些本质的区别。 局部函数与闭包函数的关联 局部函数&#xff08;Nested Function&#…

Python hashlib 模块

Python 的 hashlib 模块提供了对哈希算法的支持&#xff0c;可以用于计算数据的哈希值&#xff0c;包括常见的哈希算法如 MD5、SHA-1、SHA-256 等。让我来详细介绍一下&#xff0c;并举例说明。 首先&#xff0c;你可以使用以下方式导入 hashlib 模块&#xff1a; python impo…

(八)ReactHooks使用规则

ReactHooks使用规则 只能在组件中或者其他自定义Hook函数中使用只能在组件的顶层调用&#xff0c;不能嵌套在if、for、其他函数中

Windows 11 安装hp 1020 plus 打印机驱动 (Ubuntu 20.04.3 LTS 部署cups局域网共享打印服务器)

1 win11 下载HP laserjet 1020 plus驱动,可以官网下载哦 链接下载 2 手动添加hp laserjet 1020驱动: 控制面板-->查看设备和打印机-->打印机和扫描仪-->添加设备-->我需要的打印机不在列表中-->通过手动添加-->按名称选择共享打印机 如果找不到&#xff0…

vue在script中使用过滤器

在 Vue.js 中&#xff0c;过滤器&#xff08;filters&#xff09;主要是用于在模板中格式化文本&#xff0c;它们并不是为了在 <script> 部分或 Vue 组件的 JavaScript 逻辑中使用的。但是&#xff0c;如果你希望在 Vue 组件的 <script> 部分执行类似过滤器的功能&…

Android应用保活实践

} override fun onBind(intent: Intent): IBinder? { return mBilder } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { //播放无声音乐 if (mediaPlayer null) { mediaPlayer MediaPlayer.create(this, R.raw.novioce) //声音设置为0 me…

【DevOps】Kubernetes中Pod的CPU和内存资源管理详解

目录 1. 基本概念 1.1 资源请求&#xff08;Requests&#xff09;和限制&#xff08;Limits&#xff09; 1.2 CPU资源 1.3 内存资源 1.4 QoS类 2. 设置方法 3. 资源设置的影响 3.1 CPU设置的影响 3.2 内存设置的影响 3.3 对调度的影响 3.4 对扩展的影响 4. 最佳实践…

Spring MVC拦截器、文件上传和全局异常处理

目录 1.拦截器1.1.什么是拦截器&#xff1f;1.2 拦截器的API1.3 拦截器的执行顺序1.5 自定义拦截器1.5 登录拦截器案例 2.文件上传2.1 添加依赖2.2 配置文件上传解析器2.3 编写控制器2.4 编写jsp页面2.5 注意事项 3.全局异常处理器3.1 异常处理思路3.2 创建异常处理器3.3 编写异…

FlinkCDC sink paimon 暂不支持exactly-once写入,而通过 幂等写

幂等写入&#xff1a; 一个幂等操作无论执行多少次都会返回同样的结果。例如&#xff0c;重复的向hashmap中插入同样的key-value对就是幂等操作&#xff0c;因为头一次插入操作之后所有的插入操作都不会改变这个hashmap&#xff0c;因为hashmap已经包含这个key-value对了。另一…

vuejs3用gsap实现动画

效果 gsap官网地址&#xff1a; https://gsap.com/ 安装gsap npm i gsap 创建Gsap.vue文件 <script setup> import {reactive, watch} from "vue"; import gsap from "gsap"; const props defineProps({value:{type:Number,default:0} }) cons…

FFmpeg编译4

CPUx86-64 TOOLCHAIN N D K / t o o l c h a i n s / x 8 6 6 4 − 4.9 / p r e b u i l t / l i n u x − x 8 6 6 4 S Y S R O O T NDK/toolchains/x86_64-4.9/prebuilt/linux-x86_64 SYSROOT NDK/toolchains/x866​4−4.9/prebuilt/linux−x866​4SYSROOTNDK/platforms/and…

Java | Leetcode Java题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; class Solution {public int calculateMinimumHP(int[][] dungeon) {int n dungeon.length, m dungeon[0].length;int[][] dp new int[n 1][m 1];for (int i 0; i < n; i) {Arrays.fill(dp[i], Integer.MAX_VALUE);}dp[n][m - 1] …

QML 实现上浮后消失的提示框

基本效果&#xff1a;上浮逐渐显示&#xff0c;短暂停留后上浮逐渐消失 为了能同时显示多个提示框&#xff0c;一是需要动态创建每个弹框 Item&#xff0c;二是弹出位置问题&#xff0c;如果是底部为基准位置就把已经弹出的往上移动。 效果展示&#xff1a; 主要实现代码&…

46、基于自组织映射神经网络的鸢尾花聚类(matlab)

1、自组织映射神经网络的鸢尾花聚类的原理及流程 自组织映射神经网络&#xff08;Self-Organizing Map, SOM&#xff09;是一种用于聚类和数据可视化的人工神经网络模型。在鸢尾花聚类中&#xff0c;SOM 可以用来将鸢尾花数据集分成不同的类别&#xff0c;同时保留数据间的拓扑…

动态规划——买卖股票的最佳时机含冷冻期

1、题目链接 leetcode 309. 买卖股票的最佳时机含冷冻期 2、题目分析 该题有我们可以定义三种状态&#xff0c;买入状态&#xff0c;可交易状态 &#xff0c;冷冻期状态 我们可以建立一个n*3的二维数组来表示这三种状态&#xff1a; 根据这个图可以看出&#xff0c; 可以从…

Linux换源

文章目录 前言具体步骤国内源推荐 前言 在 Linux 发行版中更换软件源&#xff08;repository&#xff09;是一个常见的操作&#xff0c;用于加速软件的下载和更新。以下是更换软件源的详细步骤&#xff1a; 具体步骤 备份原始源列表&#xff1a; 在更改任何内容之前&#xff…

sqlalchemy给表新增注释和额外信息

sqlalchemy给表新增注释和额外信息 sqlalchemy使用__table_args__给表新增注释和额外信息,示例: class UserModel(CommonModel):__tablename__ = user # 表名称__table_args__ = {"mysql_engine": "MyISAM", # 设置数据表引擎,默认使用innodb引擎&quo…

不到3毛钱的SOT23和SOT89封装18V耐压低功耗高PSRR高精度LDO稳压芯片ME6231电流0.5A电压3.3V和1.8V

前言 SOT23-5封装ME6231外观和丝印 一款国产LDO&#xff0c;某些场合&#xff0c;要把1117扔了吧&#xff0c;SOT23封装&#xff0c;虽然不是最小&#xff0c;但也是够小的了。 参考价格&#xff1a;约0.25元 概述 ME6231 系列是以 CMOS 工艺制造的 18V 耐压、低功耗、高 PSR…

2024-06-23 操作系统实验5——模拟页式存储管理

文章目录 一、实验目的二、实验内容三、实验过程四、结果测试五、实验总结和说明 补录与分享本科实验&#xff0c;以示纪念。 一、实验目的 通过编写和调试请求页式存储管理的模拟程序以加深对请求页式存储管理方案的理解。 二、实验内容 页面淘汰算法可采用FIFO置换算法&a…

yolo评价指标

【目标检测】YOLOv5&#xff1a;添加漏检率和虚检率输出 https://www.cnblogs.com/sixuwuxian/p/18064044 【YOLOv5】推理、训练、验证参数解释_yolov5推理-CSDN博客 详解&#xff1a;yolov5中推理时置信度&#xff0c;设置的conf和iou_thres具体含义_con-thres和iou-thres分…