转自:http://club.topsage.com/thread-579104-1-1.html
随着时代发展,javascript阵营里面出现了越来越多的优秀的框架,大大简化了我们的开发工作,在我们使用这些框架的时候是不是也应该饮水思源想想它们都是怎样构建起来的呢?如果你不满足于仅仅是使用一些现成的API,而是深入了解它们内部的实现机制(照某人的说法, API是贬值最快的东西),最好的办法就是阅读它们的源代码了,前提是你读得懂。
最近两天研究了一下jQuery的源码,在这里将本人一些粗浅认识分享出来,不当之处请各位指正。好了,下面我们就来看看jQuery大概是怎样工作的,我假定你已经具备了一些基本的javascript知识,如果基础不够俺推荐你阅读《JavaScript高级程序设计》和《悟透JavaScript》这两本书。本文不适合对js里面的类、对象、函数、prototype等概念没有了解的朋友。
我们从最开始的说起:
首先构造一个对象给使用者,假定我们这个框架叫 Shaka
var Shaka = function(){};
这里我们创建了一个空函数,里面什么也没有,这个函数实际上就是我们的构造函数。为了让我们生成的对象能够调用在prototype里定义出来的方法, 我们需要用原型的方式(把Shaka当作是一个类)给Shaka添加一些方法,于是定义:
- Shaka.fn = Shaka.prototype = {};
复制代码
这里的Shaka.fn相当于Shaka.prototype的别名,方便以后使用,它们指向同一个引用。
OK,我们添加一个sayHello的方法, 给Shaka添加一个参数,这样这个框架最基本的样子已经有了,如果它有生命的话那么它现在是1岁, 看代码:
- <script type="text/javascript">
- var Shaka = function(age){ this.age = age; };
- Shaka.fn = Shaka.prototype = { sayHello: function() { alert('I am a little baby, my age is ' + this.age + ' years old.'); }};
- var babyShaka = new Shaka(1);
- babyShaka.sayHello();
- </script>
复制代码
好啦,先别激动, 我们注意到这个框架跟jQuery在使用上是有一些差别的, 比如在jq 中我们可以这样写:
- jQuery('#myid').someMethod();
复制代码
这是怎样做到的呢, 也就是说 jQuery()这个构造函数返回了一个jQuery的对象实例,因此我们可以在上面调用它的方法,所以Shaka的构造函数应该返回一个实例,它看起来应该是这个样子:
- var Shaka = function(){ return //返回Shaka的实例; };
复制代码
那么我们要如何取得一个Shaka的实例呢, 我们先来回顾一下使用prototype方式来模拟类的时候 var someObj = new MyClass(); 这个时候实际上是创建一个新对象someObje,把新对象作为this指针,调用 MyClass函数,即类的构造函数, 然后 someObj 就获得了在 MyClass.prototype里面定义的方法, 这些方法内的this指针指当前对象实例。
在jQuery中使用了一个工厂方法来创建一个实例,这个方法位于jQuery.prototype中, 现在我们重新来定义Shaka.prototype, 给它添加一个init方法用于返回一个Shaka的实例, 并且把Shaka的构造函数稍稍改变一下:
- var Shaka = function(age) { return new Shaka.fn.init(age); };
- Shaka.fn = Shaka.prototype = {
- init: function(age) { this.age = age; return this; },
- sayHello: function() { alert('I am a little baby, my age is ' + this.age + ' years old.'); }
- };
复制代码
Shaka.fn.init.prototype = Shaka.fn;//这里new Shaka.fn.init(age)创建的对象具有init方法的prototype指向对象的方法 , 因此我们将init方法的prototype指向 Shaka的prototype, 这样创建出来的对象就具有了Shaka.prototype里面定义的方法。
OK,现在我们的小宝宝变成大一点的宝宝了,打个招呼先:
- <script type="text/javascript">
- var Shaka = function(age) { return new Shaka.fn.init(age); };
- Shaka.fn = Shaka.prototype = {
- init: function(age) { this.age = age; return this; },
- sayHello: function() { alert('I am a little big baby, my age is ' + this.age + ' years old.'); }
- };
- Shaka.fn.init.prototype = Shaka.fn;
- Shaka(2).sayHello();
- </script>
复制代码
嗯,好象有点样子了,但是光这样还不行,来点实际的, 我们在新框架中实现jquery里val()方法的部分功能,这个方法不加参数调用时返回指定ID的input的值,加参数时为设定这个input的值,与jQery一样,我们约定使用id来查找对象时使用"#"符号。把要查找的目标ID作为构造函数的参数传进去,我们给Shaka.prototype添加一个val()方法, 给Shaka添加一个selector的属性用于存储我们要查找的目标。
- Shaka.fn = Shaka.prototype = {
- init: function(selector) { this.selector = selector; return this; },
- val: function(newValue) { //方法实现代码 }
- };
- var Shaka = function(selector) { return new Shaka.fn.init(selector); };
复制代码
- <form method="post" action="" name="myform">
- 我几岁了? <br />
- <input id="myInput" type="text" value="Hello world!" size="50" />
- </form>
- <script type="text/javascript">
- var Shaka = function(selector) { return new Shaka.fn.init(selector); };
- Shaka.fn = Shaka.prototype = {
- init: function(selector) { if(selector) this.selector = selector; return this; },
- val: function(newValue) {
- //start val function body
- if(!(this.selector && this.selector.indexOf('#') == 0 && this.selector.length != 1))
- return; //简单地判断传入值非法, 最好使用正则
- var id = this.selector.substring(1);
- var obj = document.getElementById(id);
- if(obj)//如果对象存在
- {
- if(newValue == undefined)
- return obj.value;//获取目标对象的值.
- obj.value = newValue;// 将目标对象的value属性设置为newValue.
- return this; //为了使方法可以连续调用。
- }
- //end val function body
- }
- };
- Shaka.fn.init.prototype = Shaka.fn;
- alert('object old value is '+Shaka('#myInput').val());
- alert(Shaka('#myInput').val('I am 3 years old now!').val());
- </script>
复制代码
到目前为止我们已经创建一个可以工作的框架雏形,为了使程序可以更方便地被调用,比如jQuery可以使用$符号来简写,我们也弄一个,在此之前我们先来回顾两个东西:
1. 我们在脚本中可以这样定义变量:
- var foo = 'someThing';
- bar = 'otherthing';
复制代码
这样两种写法都是合法的,但是意义完全不同, 第一个语句创建了一个新的变量,而第二个是定义了window对象的一个属性,相当于window.bar = 'otherthing';, 因此我们想使我们的Shaka具有这样的调用方式能力: $.someMethod();就需要将Shaka设置为window的一个属性, 于是我们的Shaka构造函数就得写成这样:
- var Shaka = window.Shaka = window.$ = function(selector) { return new Shaka.fn.init(selector); };
复制代码
2. javascript的匿名函数.
创建并执行一个匿名函数的基本形式: (function(){ alert('Hello World!'); })(); 为什么要用到匿名函数呢,因为我们不想把Shaka的内部实现暴露出来,这样容易与其它代码冲突,只提供一个单一的入口,我们可以这样测试一下:
- <script type="text/javascript">
- (function(){
- function privateFunction(){ alert('You can not see me, haha'); };
- })();
- function publicMethod() {alert('I am public');};
- alert('匿名函数内部的函数是不可访问的, privateMethod 目前是: ' + typeof privateMethod);
- alert('全局函数可访, publicMethod 目前是: ' + typeof publicMethod);
- </script>
复制代码
然后,还有一个问题需要解决,俺们的框架做出来了但是还很简陋,在这之前我们需要让它与其它的框架协同工作,因此带来一个问题, 如果我们都使用$作为简写形式就会冲突了, 象jQuery一样,我们需要提供一个noConfilit的方法“出让”$的使用权。在我们的程序最开始处加入下面的代码:
意思是将此前定义的$对象引用放到 _$ 中, 然后我们再给Shaka扩展一个方法出来, 如果其它开发者需要自行扩展的话也可以使用这个方式(jQuery的extend方法提供了更为强大的功能,请大家自行研究):
- (function($){ //extend method definition. })(Shaka);
复制代码
意思是将Shaka作为这个匿名函数的参数来调用这个方法。
前面我们讲过 Shaka.fn 就是 Shaka.prototype 的别名,因此我们要在Shaka.prototype 里面添加新的方法就可以写成这样:
- (function($){
- $.fn.noConflict = function(){
- window.$ = _$;//把$还给在开始处取得的引用.
- };
- })(Shaka);
复制代码
现在我们来看一个完整的:
- <form method="post" action="" name="myform">
- <h1> 我几岁了?</h1> <br />
- <input id="myInput" type="text" value="Hello world!" size="50" />
- <br /><br />
- <input id="otherInput" type="text" size="50" />
- </form>
- <script type="text/javascript">
- //我们在这里模拟一下在这之前如果加载了其它框架的情形, 这个时候window.$不为空.
- window.$ = { whoAmI: function(){ alert('This function result is from other js lib.');} };
- (function(){ // 创建最外层匿名函数.
- window._$ = window.$;//将别的框架定义的$暂存.
- //给Shaka加上$ 的别名.
- var Shaka = window.Shaka = window.$ = function(selector) { return new Shaka.fn.init(selector); };
- Shaka.fn = Shaka.prototype = {
- init: function(selector) { if(selector) this.selector = selector; return this; },
- val: function(newValue) {
- //start val function body
- if(!(this.selector && this.selector.indexOf('#') == 0 && this.selector.length != 1))
- return; //简单地判断传入值非法, 最好使用正则
- var id = this.selector.substring(1);
- var obj = document.getElementById(id);
- if(obj)//如果对象存在
- {
- if(newValue == undefined)
- return obj.value;//获取目标对象的值.
- obj.value = newValue;// 将目标对象的value属性设置为newValue.
- return this; //为了使方法可以连续调用, 返回当前实例。
- }
- //end val function body
- }
- };
- Shaka.fn.init.prototype = Shaka.fn;
- })();
- //扩展新的方法.
- (function($){
- //alert(obj.fn);
- $.noConflict = function(){
- window.$ = window._$;//把$还给在开始处取得的引用.
- };
- })(Shaka);
- //如果没有引入其它的框架,可以这么写
- //alert('object old value is '+$('#myInput').val());
- //alert($('#myInput').val('I am 3 years now!').val());
- //强制使用完整名称.
- Shaka.noConflict();
- alert('object old value is '+Shaka('#myInput').val());
- alert(Shaka('#myInput').val('I am 5 years old now!').val());
- //Shaka('#otherInput').val('这里的值是使用Shaka(\'#otherInput\').val()方法来写入的哦');
- //或者可以这样写也行,仍然使用$, 把Shaka作为匿名函数的参数$传进去。
- (function($){
- //又可以用$了, 哈哈
- $('#otherInput').val('这里的值是使用Shaka(\'#otherInput\').val()方法来写入的哦');
- })(Shaka);
- //现在仍然可以使用$调用其它框架的方法.
- $.whoAmI();
- </script>
复制代码
现在好象不错了,我们的Shaka baby已经5岁了;) , 当然这还只是个简陋的东西,要实现健壮而强大的功能还需要付出很多努力, 希望诸位爹妈把自己的孩子培养成人才, good luck!
分享到:
相关推荐
每篇文章都旨在帮助读者从零开始,逐步深入学习和掌握jQuery的各种使用技巧。 ### 开发环境搭建 学习jQuery的第一步是搭建开发环境。在Visual Studio中可以方便地配合使用jQuery,可以通过包管理器如NuGet安装...
这个“从零开始学习jQuery”系列教程旨在帮助初学者快速掌握jQuery的核心概念和技术,同时也适合有一定jQuery基础的开发者查找技巧和解决方案。 在入门篇中,首先介绍了jQuery的基本概念,它是一个脚本库,而不是...
### 从零开始学jQuery:全面解析与实践 #### 引言:为何选择jQuery? jQuery,作为一款跨浏览器的JavaScript库,自问世以来便迅速占领了前端开发领域的一席之地。它之所以广受开发者青睐,究其原因在于其提供了...
学习 jQuery 的旅程从理解基本概念开始,逐步掌握选择器、DOM 操作、事件处理和动画。通过实践和阅读高质量的资源,如《jQuery 实战》一书,可以深化理解并提高技能。记住,jQuery 的目标是简化 JavaScript 开发,让...
本教程“jQueryEasyUI从零开始学源码part1”旨在帮助初学者深入理解jQuery EasyUI的工作原理,通过源码分析来提升开发技能。 首先,我们需要了解jQuery EasyUI的基础概念。jQuery是一个轻量级的JavaScript库,简化...
### 从零开始学习jQuery(二):工具函数详解 #### 概述 在深入探讨jQuery工具函数之前,我们先简单回顾一下jQuery的基本概念。jQuery是一个快速、简洁且功能强大的JavaScript库,它极大地简化了HTML文档遍历、...
5. **前端框架集成**: 许多前端框架如Bootstrap、AngularJS等都与jQuery兼容,可以结合使用。 总的来说,jQuery是Web开发中不可或缺的工具,它极大地提高了JavaScript编程的效率和可读性。通过深入学习和实践,你...
Easyui则在此基础上,封装了许多常见的UI组件,如数据网格、下拉菜单、对话框、表格、表单等,使得开发者无需从零开始编写复杂的CSS和JavaScript代码,就能快速构建出美观、功能丰富的后台管理界面。 1. **jQuery....
总的来说,“jQuery+easyui应用框架”提供了一个便捷的起点,开发者可以在此基础上快速搭建后台管理系统,减少了从零开始编码的工作量。由于其组件化和模块化的特性,维护和扩展也相对容易,非常适合中小型项目或...
《架构探险从零开始javaweb框架》这本书深入浅出地介绍了如何构建Java Web应用程序,是初学者和有经验的开发者提升技术理解的好资源。它涵盖了从基础到进阶的各种主题,旨在帮助读者掌握Java Web开发的核心技术。...
Jquery是继prototype之后又一个优秀的Javascrīpt框架。它是轻量级的js库(压缩后只有21k) ,它兼容CSS3,还兼容各种浏览器 (IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+)。jQuery使用户能更方便地处理...
这些工具集成了许多常见的导航和交互功能,可以快速搭建高效、美观的界面,而无需从零开始编写代码。 总结来说,"JQuery导航框架.7z"这个资源包提供了丰富的jQuery实现的导航解决方案,包括菜单、tab和图片处理特效...
"JavaScript从零开始学"是一套针对初学者的教程,旨在帮助完全不懂编程的人逐步掌握JavaScript的核心技术和实际应用。 首先,我们需要理解JavaScript的基础语法,包括变量声明(var、let、const)、数据类型(如...