再起航,我的学习笔记之JavaScript设计模式27(链模式)
链模式
概念介绍
链模式(Operatc of Responsibility):
通过在对象方法中将当前对象返回,实现对同一个对象多个方法的链式调用。从而简化对该对象的多个方法的多次调用时,对该对象的多次引用。
原型式继承
链模式顾名思义就是像链子一样一个接一个的,我们可以通过点语法在一个方法的后面接着调用另一个方法,那么这种模式是怎么做到的呢?一般来说链模式是基于原型继承的,并且在每一个原型方法的实现上都返回当前对象this,使当前对象一直处于原型链作用域的顶端。这样我们就可以实现链式调用
我们创建一个对象A,并且给A的原型对象上添加一个length属性,和size方法,如果我们要调用的话就要通过new来创建新对象访问
var A=function(){}
A.prototypee={
length:2,
size:function(){
return this.length;
}
}
var a=new A();
console.log(a.size());

我们看到这样调用我们可以正常访问,但是下面两种方式去访问程序就会报错
console.log(A.size())

因为size绑定在A的原型上没有绑定在其自身上。
console.log(A().size())

因为A函数对象执行的结果没有返回值所以找不到size方法
上述两种方式都是因为size方法绑定在A类的原型上导致的。那么我们如果能让其访问呢?
我们可以借助另一个对象来实现。
var A=function(){
return B;
}
var B=A.prototypee={
length:2,
size:function(){
return this.length;
}
}
我们再来看看
console.log(A().size());

获取元素
我们看到现在这个A().size()的形态是不是就有链式结构的雏形了,如果这个A()能获取对象该多好,那我们接着往下面拓展功能
var A=function(){
return A.fn;
}
A.fn=A.prototypee={}
var A=function(selector){
return A.fn.init(selector);
}
A.fn=A.prototype={
init:function(selector){
return document.getElementById(selector)
},
length:2,
size:function(){
return this.length;
}
}
console.log(A('demo'));

现在我们已经能获取到元素了,但是如果想一级一级的去调用,我们还要让A对象返回的结果能拥有A.fn中的方法,这个时候我们就可以通过返回this来达到我们的目的
var A=function(selector){
return A.fn.init(selector);
}
A.fn=A.prototype={
init:function(selector){
//作为当前对象的属性值保存
this[0]=document.getElementById(selector);
//校正length属性
this.length=1;
//返回当前对象
return this;
},
length:2,
size:function(){
return this.length;
}
}
我们来测试一下
var demo=A('demo');
console.log(demo);
console.log(A('demo').size());

如果想把结果像数组那样访问,我们可以将他们的属性值顺序地设置为数字索引。为了更像数组我们还校正了它的length属性
但我们这样做有个弊端,就是后面获取的对象会把我们前面的对象覆盖掉
var test=A('container');
console.log(demo);

出现这种情况的原因是因为每次在A的构造函数中返回的A.fn.init(selector)对象都指向同一个对象造成的,我们直接使用new来创建即可
var A=function(selector){
return new A.fn.init(selector);
}
console.log(A('demo'))
console.log(A('container'))
console.log(A('demo').size())
我们发现虽然我们解决了元素覆盖的问题,但是我们那种链式的写法好像也失效了,为什么会出现这种情况呢?
这是因为A.fn.init(selector)与new A.fn.init(selector)的实现的差别造成的,牵着返回的this指向当前的对象,而后者用new对对象内的属性进行了复制,所以this指向的就不当前对象了,我们来测试说明一下。
init:function(selector){
this[0]=document.getElementById(selector);
this.length=1;
console.log(this===A.fn,this===A.prototypee,this);
return this;
}

A.fn.init(selector)返回结果如下

new A.fn.init(selector)返回结果如下

那么我们如何去解决这个问题呢,其实只用将构造函数的原型指向一个已存在的对象即可
A.fn.init.prototype=A.fn;
我们再试试
var A=function(selector){
return new A.fn.init(selector);
}
A.fn=A.prototype={
init:function(selector){
this[0]=document.getElementById(selector);
this.length=1;
return this;
},
length:2,
size:function(){
return this.length;
}
}
A.fn.init.prototype=A.fn;
console.log(A('demo').size())

好了现在我们可以接着像之前那样调用了
方法拓展
那么现在我们也能获取到对象了也能调用方法了,那我们怎么通过点语法链式使用呢,我们又要如何添加呢?
//对象拓展
A.extend=A.fn.extend=function(){
//拓展对象从第二个参数算起
var i=1,
//获取参数长度
len=arguments.length,
//第一个参数为源对象
target=arguments[0],
//拓展对象中属性
j;
//如果只穿一个参数
if(i==len){
//源对象为当前对象
target=this;
//i从0计数
i--;
}
//遍历参数中拓展对象
for(;i<len;i++){
//遍历拓展对象中的属性
for(j in arguments[i]){
//拓展源对象
target[j]=arguments[i][j];
}
}
//返回源对象
return target;
}
我们来调用试试
var demo=A.extend({first:1},{second:2},{third:3});
console.log(demo);
A.extend(A.fn,{version:'1.0'});
console.log(A('demo').version);
A.fn.extend({getVersion:function(){return this.version}})
console.log(A('demo').getVersion());
A.extend(A,{names:'李四'});
console.log(A.names);

实现链式调用
A.extend({
//分割带“-”样式,变为驼峰式写法
camelCase:function(str){
return str.replace(/\-(\w)/g,function(all,letter){
return letter.toUpperCase();
});
}
});
A.fn.extend({
//设置css样式
css:function(){
var arg=arguments,
len=arg.length;
if(this.length<1){
return this;
}
//只有一个参数时
if(len===1){
//如果为字符串则为获取一个元素CSS样式
if(typeof arg[0]==='string'){
//IE
if (this[0].currentStyle) {
return this[0].currentStyle[name];
} else{
return getComputedStyle(this[0],false)[name];
}
//为对象时则设置多个样式
}else if(typeof arg[0]==='object'){
//遍历每个样式
for (var i in arg[0]) {
for(var j=this.length-1;j>=0;j--){
//分割-为驼峰式写法
this[j].style[A.camelCase(i)]=arg[0][i];
}
}
}
//两个参数则设置一个样式
}else if(len===2){
for (var j=this.length-1;j>=0;j--) {
this[j].style[A.camelCase(arg[0])]=arg[1];
}
}
return this ;
}
})
A.fn.extend({
//设置属性
attr:function(){
var arg=arguments,
len=arg.length;
if(this.length<1){
return this;
}
//如果一个参数
if (len===1) {
//为字符串获取第一个元素属性
if(typeof arg[0]==='string'){
return this[0].getAttribute(arg[0]);
}
//为对象设置每个元素的多个属性
else if(typeof arg[0]==='object'){
//遍历属性
for (var i in arg[0]) {
for (var j=this.length-1;j>=0;j--) {
this[j].setAttribute(i,arg[0][i]);
}
}
}
//两个参数则设置每个元素单个属性
}else if(len===2){
for (var j=this.length-1;j>=0;j--) {
this[j].setAttribute(arg[0],arg[i]);
}
}
return this;
}
})
A.fn.extend({
//获取或设置元素的内容
html:function(){
var arg=arguments,
len=arg.length;
//如果没参数则取第一个元素的内容
if (len===0) {
return this[0]&&this[0].innerHTML;
}else{
//一个参数则设置每个元素的内容
for (var i=this.length-1;i>=0;i--) {
this[i].innerHTML=arg[0];
}
}
return this;
}
})
A.fn.extend({
//添加时间
on:(function(){
//如果支持DOM2级事件
if(document.addEventListener){
return function(type,fn){
var i=this.length-1;
for(;i>=0;i--){
this[i].addEventListener(type,fn,false);
}
return this;
}
//IE浏览器DOM2级事件
}else if(document.attachEvent){
return function(type,fn){
var i=this.length-1;
for (;i>=0;i--) {
this[i].addEvent('on'+type,fn);
}
return this;
}
//不支持DOM2级浏览器添加事件
}else{
return function(type,fn){
var i=this.length-1;
for(;i>=0;i--){
this[i]['on'+type]=fn;
}
return this;
}
}
})()
})
我们来看一下效果
A('demo').css({
height:'30px',
borer:'1px solid #000',
'background-color':'red'
})
.attr('class','demo')
.html('添加文字')
.on('click',function(){
console.log('触发点击事件');
});

总结
JavaScript中的链模式的核心思想就是通过在对象中的每个方法调用执行完毕后返回当前对象this来实现,由于链模式使得代码紧凑简洁而高效,目前的主流代码库都已该模式作为一种风格,比如我们最熟悉的jQuery。
也谢谢大家看到这里:)如果你觉得我的分享还可以请点击推荐,分享给你的朋友让我们一起进步~
好了以上就是本次分享的全部内容,本次示例参考自JavaScript设计模式一书,让我们一点点积累一点点成长,希望对大家有所帮助。
欢迎转载,转载请注明作者,原文出处。
再起航,我的学习笔记之JavaScript设计模式27(链模式)的更多相关文章
- 再起航,我的学习笔记之JavaScript设计模式08(建造者模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...
- 再起航,我的学习笔记之JavaScript设计模式09(原型模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...
- 再起航,我的学习笔记之JavaScript设计模式11(外观模式)
经过一段时间的学习与分享,我们对创建型设计模式已经有了一定的认识,未来的一段时间里我们将展开新的篇章,开始迈入结构性设计模式的学习. 结构性设计模式与创建型设计模式不同,结构性设计模式更偏向于关注如何 ...
- 再起航,我的学习笔记之JavaScript设计模式14(桥接模式)
桥接模式 桥接模式(Bridge): 在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦 从定义上看桥接模式的定义十分难以理解,那么我们来通过示例来演示什么是桥接模式. 现在我们需要做一个导航 ...
- 再起航,我的学习笔记之JavaScript设计模式17(模板方法模式)
模板方法模式 由模板方法模式开始我们正式告别结构型设计模式,开始行为型设计模式的学习分享 行为型设计模式用于不同对象之间职责划分或算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或对象之间的交流模 ...
- 再起航,我的学习笔记之JavaScript设计模式20(策略模式)
策略模式 策略模式(Strategy):将定义的一组算法封装起来,使其相互之间可以替换.封装的算法具有一定的独立性,不会随客户端变化而变化. 其实策略模式在我们生活中可应用的地方还是比较多的,比如在商 ...
- 再起航,我的学习笔记之JavaScript设计模式22(访问者模式)
访问者模式 概念介绍 访问者模式(Visitor): 针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法 解决低版本IE兼容性 我们来看下面这段代码,这段代码,我们封装了一个绑定 ...
- 再起航,我的学习笔记之JavaScript设计模式24(备忘录模式)
备忘录模式 概念介绍 备忘录模式(Memento): 在不破坏对象的封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态. 简易分页 在一般情况下我们需要做 ...
- 再起航,我的学习笔记之JavaScript设计模式25(迭代器模式)
迭代器模式 概念介绍 迭代器模式(Iterator): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素. 迭代器 程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍 ...
随机推荐
- 使用jmeter执行多条sql语句
注意2个地方 1. [JDBC Connection Configuration] 在配置DataBase URL的时候,加上allowMultiQueries=true参数如: jdbc:MySQL ...
- 七字真言解读TCP三次握手
三次握手所谓的"三次握手"即对每次发送的数据量是怎样跟踪进行协商使的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送.接收完毕后何时撤消联系,并建立虚连接. 一.七 ...
- java开发网易电话面试 一面总结
晚上八点多自己在看视频的时候突然接到杭州来的一个电话,当时觉得很奇怪,突兀,接通之后被告知是杭州网易打来的,没有简单的自我介绍,没有多余的废话,直接入主题,吓得我心里怪紧张的,完全没有准备,但是也没有 ...
- hdu 3722 二分图 最优完备匹配 KM算法
这题只要想到是最优完备匹配就行了: 题意:给出n个字符串,若两两相连,将前一个反置添加到后一个后面,相连的值为两个字串从头开始相等的字符个数: 问如何匹配得出最大值: 思路:建图,套模板. 代码: # ...
- 数据库学习任务一:使用vs2010建立数据库
数据库应用程序的开发流程一般主要分为以下几个步骤: 创建数据库 使用Connection对象连接数据库 使用Command对象对数据源执行SQL命令并返回数据 使用DataReader和DataSet ...
- Vuforia开发完全指南---Vuforia概述
Vuforia概述 AR(Augmented Reality)增强现实,想必大家都已经很熟悉了.这是当下最热的技术之一,是利用计算机视觉和计算机图像学领域的相关知识将虚拟世界融入到现实生活当中.AR和 ...
- MITNIK ATTACK
Https 443 http 80 TCP/IP 协议栈:将数据封装包头 传输层报头 Ack回复确认位 FIN结束位 SIN 开始位 RST 重置位 Seq 序号位 网络层报头 目的地址 原地址 报文 ...
- 201521123060 《Java程序设计》第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 2. 书面作业 1.clone方法 1.1 Object对 ...
- 201521123029《Java程序设计》第五周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 答:1. 课上讲了匿名内部类的使用,其中内部类就是定义在另一个类里面的类,与之相 ...
- 201521123025 《Java程序设计》第1周学习总结
1. 本章学习总结 (1)对JAVA的历史有了初步了解 (2)学会安装JDK和设置JAVA_HOME,PATH,CLASSPATH环境变量 (3)范围:JDK>JRE>JVM 2. 书面作 ...