再起航,我的学习笔记之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): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素. 迭代器 程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍 ...
随机推荐
- Django创建应用、模型、配置后台自动管理
1.创建应用 python manage.py startapp myblog 2.应用结构 3.创建模型(models.py) from django.db import models # Crea ...
- exjs上传图片异常:com.jspsmart.upload.SmartUploadException: File can't be saved (1120).
错误: 文件名格式不对:未命??.jpg SmartUpload mySmartUpload = new SmartUpload(); com.jspsmart.upload.File myFile ...
- jmeter 实现登录一次,多次操作登录后的某一个功能
- C# .NET Socket 简单实用框架
背景: 首先向各位前辈,大哥哥小姐姐问一声好~ 这是我第一次写博客,目前为一个即将步入大四的学生,上学期在一家公司实习了半年,后期发现没有动力,而且由于薪水问题(废话嘛),于是跳槽到这家新的公司. 说 ...
- java常见面试题(二)
1.java集合类 Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements).JavaSDK不提供直接继承自Collect ...
- 基础知识(C#语法、数据库SQL Server)回顾与总结
前言 已经有大概一个多月没有更新博客,可能是开始变得有点懒散了吧,有时候想写,但是又需要额外投入更多的时间去学习,感觉精力完全不够用啊,所以为了弥补这一个多月的潜水,决定写一篇,衔接9月未写博客的空缺 ...
- MySQL索引实战经验总结
MySQL索引对数据检索的性能至关重要,盲目的增加索引不仅不能带来性能的提升,反而会消耗更多的额外资源,本篇总结了一些MySQL索引实战经验. 索引是用于快速查找记录的一种数据结构.索引就像是数据库中 ...
- 团队作业7---Alpha冲刺值事后诸葛
一.设想和目标 1.我们的软件要解决什么问题? 解决教师和助教对实验报告查重的问题,拥有两个用户:1.教师或助教:查看学生实验报告的重复率:4.学生:上传实验报告. 2.是否定义得很清楚?是否对典型用 ...
- 201521123100《Java程序设计》第八周学习总结
---恢复内容开始--- 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 本次作业题集集合 1.List中指定元素的删除(题目4-1) 1.1 ...
- 201521123079 《Java程序设计》第1周学习总结
1. 本周学习总结 了解学习了JAVA的开发环境的基础内容以及JDK,JRE等,学会用eclipse编写简单的代码 2. 书面作业 Q1.为什么java程序可以跨平台运行?执行java程序的步骤是什么 ...