开发者社区> 华章计算机> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

jQuery技术内幕:深入解析jQuery架构设计与实现原理. 2.2 总体结构

简介:
+关注继续查看

2.2 总体结构

构造jQuery对象模块的总体源码结构如代码清单2-1所示。

代码清单2-1 构造 jQuery 对象模块的总体源码结构

 16 (function( window, undefined ) {

        // 构造 jQuery 对象

 22    var jQuery = (function() {

 25       var jQuery = function( selector, context ) {

 27              return new jQuery.fn.init( selector, context, rootjQuery );

 28          },

              // 一堆局部变量声明

 97       jQuery.fn = jQuery.prototype = {

 98          constructor: jQuery,

 99          init: function( selector, context, rootjQuery ) { ... },

              // 一堆原型属性和方法

319       };

322       jQuery.fn.init.prototype = jQuery.fn;

324       jQuery.extend = jQuery.fn.extend = function() { ... };

388       jQuery.extend({

              // 一堆静态属性和方法

892       });

955       return jQuery;

 957    })();

         // 省略其他模块的代码

9246     window.jQuery = window.$ = jQuery;

9266 })( window );

下面简要梳理下这段源码。

第16~9266行是最外层的自调用匿名函数,第1章中介绍过,当jQuery初始化时,这个自调用匿名函数包含的所有JavaScript代码将被执行。

第22行定义了一个变量jQuery,第22~957行的自调用匿名函数返回jQuery构造函数并赋值给变量jQuery,最后在第9246行把这个jQuery变量暴露给全局作用域window,并定义了别名$。

在第22~957行的自调用匿名函数内,第25行又定义了一个变量jQuery,它的值是jQuery构造函数,在第955行返回并赋值给第22行的变量jQuery。因此,这两个jQuery变量是等价的,都指向jQuery构造函数,为了方便描述,在后文中统一称为构造函数jQuery()。

第97~319行覆盖了构造函数jQuery()的原型对象。第98行覆盖了原型对象的属性constructor,使它指向jQuery构造函数;第99行定义了原型方法jQuery.fn.init(),它负责解析参数selector和context的类型并执行相应的查找;在第27行可以看到,当我们调用jQuery构造函数时,实际返回的是jQuery.fn.init()的实例;此外,还定义了一堆其他的原型属性和方法,例如,selector、length、size()、toArray()等。

第322行用jQuery构造函数的原型对象jQuery.fn覆盖了jQuery.fn.init()的原型对象。

第324行定义了jQuery.extend()和jQuery.fn.extend(),用于合并两个或多个对象的属性到第一个对象;第388~892行执行jQuery.extend()在jQuery构造函数上定义了一堆静态属性和方法,例如,noConflict()、isReady、readyWait、holdReady()等。

看上去代码清单2-1所述的总体源码结构有些复杂,下面把疑问和难点一一罗列,逐个分析。

1)为什么要在构造函数jQuery()内部用运算符new创建并返回另一个构造函数的实例?

通常我们创建一个对象或实例的方式是在运算符new后紧跟一个构造函数,例如,newDate()会返回一个Date对象;但是,如果构造函数有返回值,运算符new所创建的对象会被丢弃,返回值将作为new表达式的值。

jQuery利用了这一特性,通过在构造函数jQuery()内部用运算符new创建并返回另一个构造函数的实例,省去了构造函数jQuery()前面的运算符new,即我们创建jQuery对象时,可以省略运算符new直接写jQuery()。

为了拼写更方便,在第9246行还为构造函数jQuery()定义了别名$,因此,创建jQuery对象的常见写法是$()。

2)为什么在第97行执行jQuery.fn = jQuery.prototype,设置jQuery.fn指向构造函数jQuery()的原型对象jQuery.prototype?

jQuery.fn是jQuery.prototype的简写,可以少写7个字符,以方便拼写。

3)既然调用构造函数jQuery()返回的jQuery对象实际上是构造函数jQuery.fn.init()的实例,为什么能在构造函数jQuery.fn.init()的实例上调用构造函数jQuery()的原型方法和属性?例如,$('#id').length和$('#id').size()。

在第322行执行jQuery.fn.init.prototype = jQuery.fn时,用构造函数jQuery()的原型对象覆盖了构造函数jQuery.fn.init()的原型对象,从而使构造函数jQuery.fn.init()的实例也可以访问构造函数jQuery()的原型方法和属性。

4)为什么要把第25~955行的代码包裹在一个自调用匿名函数中,然后把第25行定义的构造函数jQuery()作为返回值赋值给第22行的jQuery变量?去掉这个自调用匿名函数,直接在第25行定义构造函数jQuery()不也可以吗?去掉了不是更容易阅读和理解吗?

去掉第25~955行的自调用匿名函数当然可以,但会潜在地增加构造jQuery对象模块与其他模块的耦合度。在第25~97行之间还定义了很多其他的局部变量,这些局部变量只在构造jQuery对象模块内部使用。通过把这些局部变量包裹在一个自调用匿名函数中,实现了高内聚低耦合的设计思想。

5)为什么要覆盖构造函数jQuery()的原型对象jQuery.prototype?

在原型对象jQuery.prototype上定义的属性和方法会被所有jQuery对象继承,可以有效减少每个jQuery对象所需的内存。事实上,jQuery对象只包含5种非继承属性,其余都继承自原型对象jQuery.prototype;在构造函数jQuery.fn.init()中设置了整型属性、length、selector、context;在原型方法.pushStack()中设置了prevObject。因此,也不必因为jQuery对象带有太多的属性和方法而担心会占用太多的内存。

关于构造函数、原型、继承等基础知识,请查阅相关的基础类书籍。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
jQuery插件实现图片墙小案例
jQuery插件实现图片墙小案例
0 0
【jquery Ajax】接口的学习与Postcode插件的使用
【jquery Ajax】接口的学习与Postcode插件的使用
0 0
DateTimePicket jQuery 日期插件,开始时间和结束时间示例
DateTimePicket jQuery 日期插件,开始时间和结束时间示例
0 0
利用JQuery上传插件Uploadify实现图片上传MongoDB并预览
利用JQuery上传插件Uploadify实现图片上传MongoDB并预览
0 0
NET MVC第七章、jQuery插件验证
NET MVC第七章、jQuery插件验证
0 0
编写自定义的JQuery插件的几个注意点
编写自定义的JQuery插件的几个注意点
0 0
关于JQuery validate表单校验插件对级联下拉框的校验问题
关于JQuery validate表单校验插件对级联下拉框的校验问题
0 0
jQuery的DOM文档对象模型,常见的事件,遍历,validate插件,自定义事件方法
jQuery的DOM文档对象模型,常见的事件,遍历,validate插件,自定义事件方法
0 0
文章
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
编程语言如何演化—— 以 JS 的 private 为例
立即下载
编程语言如何演化-以JS的private为例
立即下载
基于VUE的单页面性能优化实践
立即下载