方法链式调用的实现

写的更少,做的更多。是JQuery的核心理念。

那么链式方法的设计与这个核心理念不谋而合。那么从深层次考虑这种设计其实就是一种Internal DSL。

DSL是指Domain Specific Language,也就是用于描述和解决特定领域问题的语言。

看一段链式代码:

$('input[type="button"]')
.eq(0).click(function() {
alert('点击我!');
}).end().eq(1)
.click(function() {
$('input[type="button"]:eq(0)').trigger('click');
}).end().eq(2)
.toggle(function() {
$('.aa').hide('slow');
}, function() {
$('.aa').show('slow');
});

看这个代码的结构:

1.找出type类型为button的input元素

2.找到第一个按钮,并绑定click事件处理函数

3.返回所有按钮,再找到第二个

4.为第二个按钮绑定click事件处理函数

5.为第三个按钮绑定toggle事件处理函数

让代码更贴近作者的思维模式;阅读代码时,让读者更容易理解代码的含义;应用DSL可以有效的提高系统的可维护性

(缩小了实现模型和领域模型的距离,提高了实现的可读性)和灵活性,并且提供开发的效率。

jQuery的这种管道风格的DSL链式代码,总的来说:

1. 节约JS代码;

2.所返回的都是同一个对象,可以提高代码的效率。

通过简单扩展原型方法并通过return this的形式来实现跨浏览器的链式调用。

利用JS下的简单工厂方法模式,来将所有对于同一个DOM对象的操作指定同一个实例。

这个原理就超简单了,如下代码:

aQuery().init().name()

分解:

a = aQuery();
a.init()
a.name()

把代码分解一下,很明显实现链式的基本条件就是要实例对象先创建好,调用自己的方法。

aQuery.prototype = {
init: function() {
return this;
},
name: function() {
return this
}
}

所以我们如果需要链式的处理,只需要在方法内部方法当前的这个实例对象this就可以了,因为返回当前实例的this,从而又可以访问自己的原型了,

这样的就节省代码量,提高代码的效率,代码看起来更优雅。

但是这种方法有一个问题是:所有对象的方法返回的都是对象本身,也就是说没有返回值,所以这种方法不一定在任何环境下都适合。

虽然Javascript是无阻塞语言,但是他并不是没阻塞,而是不能阻塞,

所以他需要通过事件来驱动,异步来完成一些本需要阻塞进程的操作,这样处理只是同步链式,

除了同步链式还有异步链式,异步链式jQuery从1.5开始就引入了Promise.

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> 链式调用$$().setName('孙丽媛-Aaron').getName()的结果:
<div id="aaron"></div> <script type="text/javascript"> var $$ = ajQuery = function(selector) {
return new ajQuery.fn.init(selector);
} ajQuery.fn = ajQuery.prototype = {
name: 'aaron',
init: function(selector) {
this.selector = selector;
return this;
},
constructor: ajQuery
} ajQuery.fn.init.prototype = ajQuery.fn ajQuery.fn.setName = function(myName) {
this.myName = myName
return this;
} ajQuery.fn.getName = function() {
$("#aaron").html(this.myName)
return this;
} $$().setName('孙丽媛-Aaron').getName(); </script>
</body>
</html>

插件接口的设计

基于插件接口设计的好处也是颇多的,其中一个最重要的好处是把扩展的功能从主体框架中剥离出去,降低了框架的复杂度。

接口的设计好比电脑上的配件如:CPU、内存、硬盘都是作为独立的模块分离出去了,但是主板提供模块的接口,

例如支持串口的硬盘,我只要这个硬盘的接口能插上,甭管是500G还是1000G的容量的硬盘,都能使用。

所以在软件设计中插件接口的提供把独立的功能与框架以一种很宽松的方式松耦合。

jQuery插件的开发分为两种:

1.一种是挂在jQuery命名空间下的全局函数,也可称为静态方法;

2.另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法。

提供的接口:

$.extend(target, [object1], [objectN])

接口的使用:

jQuery.extend({
data:function(){},
removeData:function(){}
}) jQuery.fn.extend({
data:function(){},
removeData:function(){}
})

jQuery的主体框架就是之前提到的那样,通过工厂模式返回一个内部的init构造器生成的对象。

但是根据一般设计者的习惯,如果要为jQuery添加静态方法或者实例方法从封装的角度讲是应该提供一个统一的接口才符合设计的。

jQuery支持自己扩展属性,这个对外提供了一个接口,jQuery.fn.extend()来对对象增加方法,

从jQuery的源码中可以看到,jQuery.extend和jQuery.fn.extend其实是同指向同一方法的不同引用。

这里有一个设计的重点,通过调用的上下文,我们来确定这个方法是作为静态还是实例处理,

在javascript的世界中一共有四种上下文调用方式:

1.方法调用模式、

2.函数调用模式、

3.构造器调用模式、

4.apply调用模式:

jQuery.extend调用的时候上下文指向的是jQuery构造器

jQuery.fn.extend调用的时候上下文指向的是jQuery构造器的实例对象了

通过extend()函数可以方便快速的扩展功能,不会破坏jQuery的原型结构,

jQuery.extend = jQuery.fn.extend = function(){...}; 这个是连等,也就是2个指向同一个函数,怎么会实现不同的功能呢?这就是this力量了!

fn与jQuery其实是2个不同的对象

jQuery.extend 调用的时候,this是指向jQuery对象(jQuery是函数,也是对象!),所以这里扩展在jQuery上。

而jQuery.fn.extend 调用的时候,this指向fn对象,jQuery.fn 和jQuery.prototype指向同一对象,扩展fn就是扩展jQuery.prototype原型对象。

这里增加的是原型方法,也就是对象方法了。所以jQuery的API中提供了以上2个扩展函数

jQuery的extend代码实现比较长,我们简单说一下重点:

aAron.extend = aAron.fn.extend = function() {
var options, src, copy,
target = arguments[0] || {},
i = 1,
length = arguments.length; //只有一个参数,就是对jQuery自身的扩展处理
//extend,fn.extend
if (i === length) {
target = this; //调用的上下文对象jQuery/或者实例
i--;
}
for (; i < length; i++) {
//从i开始取参数,不为空开始遍历
if ((options = arguments[i]) != null) {
for (name in options) {
copy = options[name];
//覆盖拷贝
target[name] = copy;
}
}
}
return target;
}

因为extend的核心功能就是通过扩展收集功能(类似于mix混入),所以就会存在收集对象(target)与被收集的数据,

因为jQuery.extend并没有明确实参,而且是通过arguments来判断的,所以这样处理起来很灵活。

arguments通过判断传递参数的数量可以实现函数重载。

其中最重要的一段target = this,通过调用的方式我们就能确实当前的this的指向,所以这时候就能确定target了。

最后就很简单了,通过for循环遍历把数据附加到这个target上了。

当然在这个附加的过程中我们还可以做数据过滤、深拷贝等一系列的操作了。

<div id="aaron"></div>

<script type="text/javascript">

var $$ = ajQuery = function(selector) {
return new ajQuery.fn.init(selector);
} ajQuery.fn = ajQuery.prototype = {
name: 'aaron',
init: function(selector) {
this.selector = selector;
return this;
},
constructor: ajQuery
} ajQuery.fn.init.prototype = ajQuery.fn ajQuery.extend = ajQuery.fn.extend = function() {
var options, src, copy,
target = arguments[0] || {},
i = 1,
length = arguments.length; //只有一个参数,就是对jQuery自身的扩展处理
//extend,fn.extend
if (i === length) {
target = this; //调用的上下文对象jQuery/或者实例
i--;
}
for (; i < length; i++) {
//从i开始取参数,不为空开始遍历
if ((options = arguments[i]) != null) {
for (name in options) {
copy = options[name];
//覆盖拷贝
target[name] = copy;
}
}
}
return target;
} ajQuery.fn.extend({
setName: function(myName) {
this.myName = myName
return this;
},
getName: function() {
$("#aaron").html(this.myName)
return this;
}
}) $$().setName('孙丽媛-Aaron').getName();

JQuery源码分析(六)的更多相关文章

  1. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

  2. [转] jQuery源码分析-如何做jQuery源码分析

    jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ...

  3. jQuery 源码分析 8: 回头看jQuery的构造器(jQuery.fn,jQury.prototype,jQuery.fn.init.prototype的分析)

    在第一篇jQuery源码分析中,简单分析了jQuery对象的构造过程,里面提到了jQuery.fn.jQuery.prototype.jQuery.fn.init.prototype的关系. 从代码中 ...

  4. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  5. jquery源码分析之一前言篇

    1.问:jquery源码分析的版本是什么? 答:v3.2.1 2.问:为什么要分析jquery源码? 答:javascript是一切js框架的基础,jquery.es6.vue.angular.rea ...

  6. jQuery源码分析-each函数

    本文部分截取自且行且思 jQuery.each方法用于遍历一个数组或对象,并对当前遍历的元素进行处理,在jQuery使用的频率非常大,下面就这个函数做了详细讲解: 复制代码代码 /*! * jQuer ...

  7. jQuery源码分析系列(转载来源Aaron.)

    声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...

  8. jQuery源码分析系列——来自Aaron

    jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...

  9. jQuery 源码分析(十六) 事件系统模块 底层方法 详解

    jQuery事件系统并没有将事件监听函数直接绑定到DOM元素上,而是基于数据缓存模块来管理监听函数的,事件模块代码有点多,我把它分为了三个部分:分底层方法.实例方法和便捷方法.ready事件来讲,好理 ...

  10. js菜鸟进阶-jQuery源码分析(1)-基本架构

    导读: 本人JS菜鸟一枚,为加强代码美观和编程思想.所以来研究下jQuery,有需要进阶JS的同学很适合阅读此文!我是边看代码(jquery2.2.1),边翻“javascript高级程序设计”写的, ...

随机推荐

  1. 转载 网页打印时设置A4大小

    最近开发项目时遇到了网页打印的问题,这是问题之二,打印宽度设置 在公制长度单位与屏幕分辨率进行换算时,必须用到一个DPI(Dot Per Inch)指标. 经过我仔细的测试,发现了网页打印中,默认采用 ...

  2. Front End中Javascript兼容问题收集(转)

    1 select标签,就有诸多不兼容: A. cloneNode方法,对于非IE浏览器没有问题,对于IE浏览器, 遇到的问题包括:     1)option selected的会clone不过去,然后 ...

  3. Oracle11g中ORA-01790

    问题源于群里有人问如何让查询的结果值+1,方法其实很简单,直接在SQL语句中+1就可以,如果有空可以用NVL处理. 但是测试的时候我使用了UNION ALL(测试的字段是varchar2类型),结果报 ...

  4. BroadcastReceiver的实例----基于Service的音乐播放器之一

    下面的程序开发了一个基于Service的音乐盒,程序的音乐将会由后台运行的Service组件负责播放,当后台的播放状态发生改变时,程序将会通过发送广播通知前台Activity更新界面:当用户单击前台A ...

  5. TCP/IP 某些最常见的错误原因码 (errno)列表

    对于在基于 UNIX 的环境中的 TCP/IP 用户,下表列出了某些最常见的错误原因码 (errno).它不是完整的错误列表.可以在文件 /usr/include/sys/errno.h 中找到 Er ...

  6. Delphi日期时间 UNIX

    Delphi日期时间,就是常见的 2014-05-02 10:37:35 --------------------------------------------------------------- ...

  7. Struts2 的验证

    概述 一个健壮的 web 应用程序必须确保用户输入是合法.有效的. Struts2 的输入验证 –基于 XWork Validation Framework 的声明式验证:Struts2 提供了一些基 ...

  8. POJ 3384

    题目大意: 给定一个多边形,给定一个圆的半径,要求在多边形中放置两个同样半径的圆,可相互覆盖,但不能超出多边形的范围,希望两个圆的面积覆盖和最大 输出任意一组满足的圆的圆心点 如果两个圆不相互覆盖,那 ...

  9. DotNetBar v12.7.0.2 Fully Cracked

    更新信息: http://www.devcomponents.com/customeronly/releasenotes.asp?p=dnbwf&v=12.7.0.2 如果遇到破解问题可以与我 ...

  10. [转]Android进程与线程基本知识

    转自:http://www.cnblogs.com/hanyonglu/archive/2012/04/12/2443262.html 本文介绍Android平台中进程与线程的基本知识. 很早的时候就 ...