当前位置: 首页 > Web前端 > vue.js

重启2019——JavaScript学习:阅读jQuery源码

时间:2023-04-01 11:27:32 vue.js

简介:2019年reacthooks成功上线,vue3.0发布alpha版本,TS使用率快速提升,大量前端的用户体验-前端开发工具得到极大优化和改进当越来越多的开发者抱怨前端学习时,最好的应对方式就是掌握基本概念。内功足够强大,才不会被别人牵着鼻子走。阅读开源代码是一个很好的方法。首先我选择jQuery是因为里面的内容没有太多抽象的设计思想。它更多的是覆盖基本内容。它还包含一些不错的设计模式,因此具有良好的性价比。jQuery是早期前端开发中非常重要的库。在手动操作DOM、浏览器差异较大的时代,jQuery通过统一和简化不同浏览器之间的API,为程序开发带来了极大的便利。所以jQuery的设计思想也是围绕这两点展开的。ps:如无特殊说明,$等同于源码示例中的jQuery。jQueryDOM查询和操作ajax请求动画动画promise(deferred)事件处理css样式兼容性问题,平滑不同浏览器之间的差异所做的主要工作jQuery面向对象的特性————>原型API设计的特性—————>函数重载jQuery对于DOM操作势在必行,所以使用成本比较低,没有特别复杂的API设计,数量少,参数简单。内部封装,为了实现jQuery的几大功能,做了很多内部封装,比如类型判断方法class2type,拆分的够细,为以后的模块化加载和性能优化预留空位;选择器引擎:Sizzle,会发现函数由于数据被缓存,如果下次遇到相同的选择器,可以跳过选择器解析过程,直接进行元素查找;jQuery的面向对象jQuery实际上是采用面向对象的方式进行程序开发。jQuery本身就是构造函数。jQuery('body').constructor===jQuery//truejQuery('body').addClass===jQuery.prototype.addClass//true//因为jQuery('body')的constructor和addClass方法指向jQuery分别自身和jQuery.prototype上的addClass方法,//所以jQuery('body')返回的对象其实是jQuery构造函数生成的实例,但是js中一般使用new运算符来生成实例,而jQuery的一般写法是$()。在这里,实际上通过某种技术省略了new运算符。首先,不管有没有new,生成的实例都是等价的。(newjQuery('body')).constructor===jQuery('body').constructor//true(newjQuery('body')).__proto__===jQuery('body').__proto__//true//这证实了使用或不使用new运算符,返回的结果是等效的。这种设计的一个优点是可以更轻松地构造jQuery对象。它的实施情况如何?看一下jQuery函数的定义:jQuery=function(selector,context){returnnewjQuery.fn.init(selector,context);};我们发现jQuery方法返回的其实是jQuery.fn。初始化的实例。同时,为了让生成的实例继承jQuery.prototype上的方法,我们需要添加一行代码:jQuery.fn.init.prototype=jQuery.prototype;关于js中的构造函数和原型的详细介绍,请参考其他资料。关于new操作符,我们都知道当构造函数没有指定返回对象时,会返回this本身。如果我们在没有new的时候显式指定返回对象为this(returnthis;),是不是也等同于new?答:不是的。这个跟函数中this的指向有关。当一个函数或方法执行时,内部this点分为四个来源func():this指向全局obj.func():this指向objcall/apply:this指向传给call的new操作的第一个参数/apply符号:这个在函数中指向一个新创建的Object对象封装和继承决定了jQuery的开发采用面向对象的方式。以及面向对象的两个基本要素:封装和继承。封装定义了一个实例是如何组装的,而继承定义了在多个实例之间共享什么(行为)。封装$.fn.init方法通过简单的$()工厂函数调用来封装jQuery对象。在init方法中,所有可能的输入源都被封装为jQuery对象。需要特别说明的一点是,$()方法除了可以接收普通的DOM对象或者HTML字符串作为输入源,返回一个jQuery对象外,还支持接收函数。这也是一个语法糖,意思是当文档准备好时调用这个函数。这种方式没有什么特别的用途,很方便定义一些在documentready中执行的逻辑。因为在实际业务中,你的代码执行的时候,可能还有很多元素没有被加载。jQuery对象的继承是基于js的原型对象。所有jQuery对象都共享$.prototype对象上的方法。同时,jQuery为自己添加了一个extend()方法,用于对象的扩展。然后,它也可以用来扩展自己的原型对象,从而实现功能的扩展。这也是jQuery插件实现的基本原理。需要预先指定的要点:jQuery.prototype===jQuery.fn。什么用途?手动输入代码时速度更快。hooksjQuery中很多地方使用了hook思想,主要是为了处理浏览器兼容性问题。在事件处理和css样式设置上尤为明显。jQuery的事件处理事件处理包括业务的绑定、分发和删除三部分。jQuery中的所有事件(包括自定义事件)都会通过这三个方法进行处理。如果遇到自定义事件或者兼容性处理等特殊情况,就会用到jQuery.event.special。jQuery.event.special实现的基础是jQuery作为浏览器事件的代理,所有需要绑定元素事件的业务逻辑最终都会交给一个统一的方法。该方法通过原生API绑定到元素上,然后当事件触发时,该方法根据事件的上下文分发业务逻辑。jQuery与事件的绑定最终缩减为jQuery.event.add方法,无论暴露的API是on()还是one()。同时,模块内部还有一个on方法,同样起到函数重载的作用,将参数处理成规范的形式,然后提交给jQuery.event.add方法进行事件绑定操作。jQuery.event.add方法非常有趣。它不直接通过原生绑定方法将处理方法绑定到元素上。相反,将EventHandler作为数据存储在元素本身中(有关存储实现,请参阅Data.js)。如果一个元素绑定了多个相同类型的事件,这些事件将以数组的形式存在。如果不直接使用handler来帮助元素的事件,那么当事件被触发时如何调用这些逻辑呢?其实就是绑定了一个调度器,这个调度器会在事件触发的时候,把存储元素本身的方法一个一个取出来执行。这是处理浏览器支持的常见事件的方法。自定义事件呢?答案是jQuery.event.special。如果执行自定义事件customEvent绑定逻辑,jQuery首先会检查jQuery.event.special.customEvent是否存在。如果存在,它将遵循jQuery.event.special.customEvent中定义的逻辑。这个对象一般包含四个方法:setup、add、teardown、'remove'。它在事件处理中作用于不同的生命周期。通过special拦截事件处理逻辑,在此基础上可以重写原生事件的行为或者添加自定义事件。如果不使用special,那么如何处理兼容性问题。如果别的?编写的逻辑变成了意大利面条代码。在事件处理中,存在三个基本要素:绑定、解除绑定和分发。对于同一个事件的兼容性处理,可能需要在这三种处理方式中加入兼容性业务处理。这样写出来的逻辑一定很复杂。如果我们以事件为单位,定义各自的三种逻辑,然后交给程序适时调用。这样,业务就会清晰很多。jQuery.event.specialsetup:事件第一次绑定到元素时调用;teardown:当事件的最后一个处理程序与元素解除绑定时调用;添加:向元素添加处理程序;remove:从元素中删除处理程序;handler:在调度事件时调用;_default:为事件添加默认行为;如果setup/teardown返回false,jQuery的bind/unbind方法(通过DOMnativeAPI)$.fn.css()方法会被执行jQuery.cssHooks中存在css样式方法相关的Hooks,分为get和set。ajax和dataType$.ajax允许接收dataType:jsonp,但是我们知道jsonp是通过