再起航,我的学习笔记之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): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素. 迭代器 程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍 ...
随机推荐
- 服务端性能测试 TPS
针对服务器端的性能,以TPS为主来衡量系统的性能,并发用户数为辅来衡量系统的性能,如果必须要用并发用户数来衡量的话,需要一个前提,那就是交易在多长时间内完成,因为在系统负载不高的情况下,将思考时间( ...
- Akka(23): Stream:自定义流构件功能-Custom defined stream processing stages
从总体上看:akka-stream是由数据源头Source,流通节点Flow和数据流终点Sink三个框架性的流构件(stream components)组成的.这其中:Source和Sink是stre ...
- Keepalive之nginx调度架构
author:JevonWei 版权声明:原创作品 单主模式Keepalive之Nginx调度 实验目的:实现Nginx调度的高可用,当一台Nginx调度器故障时,启用备用的Nginx调度,在架构中, ...
- Java jdk 快速配置
JAVA_HOME C:\Program Files\Java\jdk1.8.0_92 Path %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; CLASSPATH ...
- Swing-JOptionPane对话框用法-入门
对话框是GUI程序中常见的界面,通常用来反馈提示信息.告警或获取用户输入.比如这种: JOptionPane是Swing中的一个对话框类,它能够提供常见的绝大多数对话框效果,本文对这个类进行介绍.需要 ...
- 201521123109《java程序设计》第七周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 ArrayList代码分析 1.1 解释ArrayList的contains源代码 源代码: pub ...
- 201521123071 《JAVA程序设计》第四周学习总结
1. 本周学习总结 1.1 1.2 在本周的学习中,主要学习了以下几点: 注释的应用,并能在Eclipse中查看 继承的基本定义,关键字super的用法,覆盖与重载 多态与is-a,instanceo ...
- 201521123056《Java程序设计》 第2周学习总结
1. 本周学习总结 String类: 不可变字符串型: 粗略介绍了枚举类型: 完全限定类名: 泛型数组列表的应用: 2. 书面作业 Q1.使用Eclipse关联jdk源代码,并查看String对象的源 ...
- 201521123087 《Java程序设计》第1周学习总结
1.学习总结 初步了解面对对象编程思想 学会安装JDK和设置JAVA_HOME,PATH,CLASSPATH环境变量 简单了解java 2.书面作业 1.为什么java程序可以跨平台运行?执行java ...
- Java课程设计—学生成绩管理系统
一. 团队名称.团队成员介绍(需要有照片) 团队名称:进击的712 团队成员 杨雪莹[组长] 201521123005 网络1511 林楚虹 201521123002 网络1511 董美凤 20152 ...